3.6 通道(channel)简介
通道(Channel):由 java.nio.channels 包定的。Channel 表示 IO 源与目标打开的连接。Channel 类似于传统的“流”。只不过 Channel本身不能直接访问数据,Channel 只能与Buffer 进行交互
3.7 通道模型
3.8 通道(Channel) 实现类
FileChannel:用于读取、写入、映射和操作文件的通道。
DatagramChannel:通过 UDP 读写网络中的数据通道。
SocketChannel:通过 TCP 读写网络中的数据。
ServerSocketChannel:可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个 SocketChannel
3.8.1 获取通道
获取通道的一种方式是对支持通道的对象调用getChannel() 方法。支持通道的类如下:
FileInputStream
FileOutputStream
RandomAccessFile
DatagramSocket
Socket
ServerSocket
获取通道的其他方式是使用 Files 类的静态方法 newByteChannel() 获取字节通道。或者通过通道的静态方法 open() 打开并返回指定通道。
3.8.2 通道的数据传输
- 将 Buffer 中数据写入 Channel
- 从 Channel 读取数据到 Buffer
1. 利用通道完成文件的复制(非直接缓冲区)
/**
* 利用通道完成文件的复制(非直接缓冲区)
*/
@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.分配指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
//3.将通道的数据存在缓冲区中
while (inChannel.read(buf) != -1) {
//切换读数据模式
buf.flip();
//4.将缓冲区的数据写到通道中
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. 使用直接缓冲区完成文件的复制(内存映射文件) ps:不推荐使用
/**
* 使用直接缓冲区完成文件的复制(内存映射文件)
*/
@Test
public void test02() {
//1.获取通道
FileChannel inChannel = null;
FileChannel outChannel = null;
//2.内存映射文件
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,
//创建
StandardOpenOption.CREATE_NEW,
//写
StandardOpenOption.WRITE);
//直接对缓冲区进行数据的读写操作
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.通道之间的数据传输(直接缓冲区) transferFrom/transferTo
/**
* 通道之间的数据传输(直接缓冲区)
*/
@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();
}
}
}
}