Channel:用於源節點與目標節點之間的連接。在Java NIO中,負責緩衝區中數據傳輸,Channel本身不存儲數據,因此需要配合緩衝區進行傳輸。
在NIO中,使用通道(Channel)基於緩衝區數據塊的讀寫。
Buffer
ByteBuffer
CharBuffer
DoubleBuffer...
主要介紹一下ByteBuffer
ByteBuffer繼承於Buffer類,ByteBuffer是個抽象類,它有兩個實現的子類HeapByteBuffer和MappedByteBuffer類
HeapByteBuffer:在堆中創建的緩衝區。就是在jvm中創建的緩衝區。
MappedByteBuffer:直接緩衝區。物理內存中創建緩衝區,而不在堆中創建。
allocate 方法(創建堆緩衝區)
public static ByteBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
return new HeapByteBuffer(capacity, capacity);
}
allocate方法創建的緩衝區是創建的HeapByteBuffer實例。
HeapByteBuffer(int cap, int lim) { // package-private
super(-1, 0, lim, cap, new byte[cap], 0);
}
從堆緩衝區中看出,所謂堆緩衝區就是在堆內存中創建一個byte[]數組。
allocateDirect創建直接緩衝區
public static ByteBuffer allocateDirect(int capacity) {
return new DirectByteBuffer(capacity);
}
我們發現allocate方法創建的緩衝區是創建的DirectByteBuffer實例。
直接緩衝區是通過java中Unsafe類進行在物理內存中創建緩衝區。
與Channel的配合使用
package com.expgiga.NIO;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
/**
* 一、Channel:用於源節點與目標節點之間的連接。在Java NIO中,負責緩衝區中數據傳輸,Channel本身不存儲數據,因此需要配合緩衝區進行傳輸。
*
* 二、Channel的實現類:
* java.nio.channels.Channel 接口:
* |-- FileChannel
* |-- SocketChannel
* |-- ServerSocketChannel
* |-- DatagramChannel
*
* 三、獲取通道Channel
* 1.Java針對支持通道的類提供了getChannel()方法
* 本地IO
* FileInputStream/FileOutputStream
* RandomAccessFile
*
* 網絡IO:
* Socket
* ServerSocket
* DatagramSocket
*
* 2.在jdk1.7中的NIO.2針對各個通道提供了靜態方法open()
*
* 3.在jdk1.7中的NIO.2的Files工具類的newByteChannel()
*
* 四、通道之間的數據傳輸
* transferFrom()
* transferTo()
*
*/
public class TestChannel {
public static void main(String[] args) throws IOException {
/*
* 1.利用通道完成文件的複製(非直接緩衝區)
*/
FileInputStream fis = null;
FileOutputStream fos = null;
FileChannel inChannel = null;
FileChannel outChannel = null;
try {
fis = new FileInputStream("1.jpg");
fos = new FileOutputStream("2.jpg");
//1.獲取通道
inChannel = fis.getChannel();
outChannel = fos.getChannel();
//2.分配指定大小的緩衝區
ByteBuffer buffer = ByteBuffer.allocate(1024);
//3.將通道中的數據緩衝區中
while (inChannel.read(buffer) != -1) {
buffer.flip();//切換成都數據模式
//4.將緩衝區中的數據寫入通道中
outChannel.write(buffer);
buffer.clear();//清空緩衝區
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (outChannel != null) {
try {
outChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inChannel != null) {
try {
inChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
* 2.利用(直接緩衝區)通道完成文件的複製(內存映射文件的方式)
*/
long start = System.currentTimeMillis();
FileChannel inChannel2 = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
FileChannel outChannel2 = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);
//內存映射文件
MappedByteBuffer inMappedBuf = inChannel2.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
MappedByteBuffer outMappedBuf = outChannel2.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());
//直接對緩衝區進行數據讀寫操作
byte[] dst = new byte[inMappedBuf.limit()];
inMappedBuf.get(dst);
outMappedBuf.put(dst);
inChannel2.close();
outChannel2.close();
long end = System.currentTimeMillis();
System.out.println("耗費的時間爲:" + (end - start));
/*
* 通道之間的數據傳輸(直接緩衝區)
*/
FileChannel inChannel3 = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
FileChannel outChannel3 = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);
inChannel3.transferTo(0, inChannel3.size(), outChannel3);
//等價於
// outChannel3.transferFrom(inChannel3, 0, inChannel3.size());
inChannel3.close();
outChannel3.close();
}
}