3.6 通道(channel)簡介
通道(Channel):由 java.nio.channels 包定的毅舆。Channel 表示 IO 源與目標(biāo)打開的連接。Channel 類似于傳統(tǒng)的“流”踪危。只不過 Channel本身不能直接訪問數(shù)據(jù),Channel 只能與Buffer 進行交互
3.7 通道模型
image.png
image.png
image.png
3.8 通道(Channel) 實現(xiàn)類
FileChannel:用于讀取贞远、寫入畴博、映射和操作文件的通道。
DatagramChannel:通過 UDP 讀寫網(wǎng)絡(luò)中的數(shù)據(jù)通道蓝仲。
SocketChannel:通過 TCP 讀寫網(wǎng)絡(luò)中的數(shù)據(jù)蜜唾。
ServerSocketChannel:可以監(jiān)聽新進來的 TCP 連接庶艾,對每一個新進來的連接都會創(chuàng)建一個 SocketChannel
3.8.1 獲取通道
獲取通道的一種方式是對支持通道的對象調(diào)用getChannel() 方法擎勘。支持通道的類如下:
FileInputStream
FileOutputStream
RandomAccessFile
DatagramSocket
Socket
ServerSocket
獲取通道的其他方式是使用 Files 類的靜態(tài)方法 newByteChannel() 獲取字節(jié)通道∶喝梗或者通過通道的靜態(tài)方法 open() 打開并返回指定通道。
3.8.2 通道的數(shù)據(jù)傳輸
- 將 Buffer 中數(shù)據(jù)寫入 Channel
image.png
- 從 Channel 讀取數(shù)據(jù)到 Buffer
image.png
1. 利用通道完成文件的復(fù)制(非直接緩沖區(qū))
/**
* 利用通道完成文件的復(fù)制(非直接緩沖區(qū))
*/
@Test
public void test01() {
FileInputStream fis = null;
FileOutputStream fos = null;
//1. 獲取通道
FileChannel inChannel = null;
FileChannel outChannel = null;
try {
fis = new FileInputStream("d:/1.mp4");
fos = new FileOutputStream("d:/2.mp4");
inChannel = fis.getChannel();
outChannel = fos.getChannel();
//2.分配指定大小的緩沖區(qū)
ByteBuffer buf = ByteBuffer.allocate(1024);
//3.將通道的數(shù)據(jù)存在緩沖區(qū)中
while (inChannel.read(buf) != -1) {
//切換讀數(shù)據(jù)模式
buf.flip();
//4.將緩沖區(qū)的數(shù)據(jù)寫到通道中
outChannel.write(buf);
buf.clear();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
;
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
;
}
if (inChannel != null) {
try {
inChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
;
}
if (outChannel != null) {
try {
outChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
;
}
}
}
2. 使用直接緩沖區(qū)完成文件的復(fù)制(內(nèi)存映射文件) ps:不推薦使用
/**
* 使用直接緩沖區(qū)完成文件的復(fù)制(內(nèi)存映射文件)
*/
@Test
public void test02() {
//1.獲取通道
FileChannel inChannel = null;
FileChannel outChannel = null;
//2.內(nèi)存映射文件
MappedByteBuffer inMapperBuf = null;
MappedByteBuffer outMapperBuf = null;
try {
inChannel = FileChannel.open(Paths.get("d:/1.mp4"),
//讀
StandardOpenOption.READ);
outChannel = FileChannel.open(Paths.get("d:/3.mp4"),
//讀
StandardOpenOption.READ,
//創(chuàng)建
StandardOpenOption.CREATE_NEW,
//寫
StandardOpenOption.WRITE);
//直接對緩沖區(qū)進行數(shù)據(jù)的讀寫操作
byte[] dst = new byte[inMapperBuf.limit()];
inMapperBuf.get(dst);
outMapperBuf.put(dst);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inChannel != null) {
try {
inChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outChannel != null) {
try {
outChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
3.通道之間的數(shù)據(jù)傳輸(直接緩沖區(qū)) transferFrom/transferTo
/**
* 通道之間的數(shù)據(jù)傳輸(直接緩沖區(qū))
*/
@Test
public void test03() {
//1.獲取通道
FileChannel inChannel = null;
FileChannel outChannel = null;
try {
inChannel = FileChannel.open(Paths.get("d:/1.mp4"));
outChannel = FileChannel.open(Paths.get("d:/4.mp4"),
StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);
//二者選其一,注意選api
// inChannel.transferTo(0, inChannel.size(), outChannel);
outChannel.transferFrom(inChannel, 0, inChannel.size());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inChannel != null) {
try {
inChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outChannel != null) {
try {
outChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}