引言
前面我们学习了NIO中的缓冲区,了解了相应的功能和相关的实现方法详见(NIO学习之简介+Buffer部分源码阅读分析记录1)。本篇博文我们主要记录一下通道的一些基础概念,并且使用通道+缓冲区实现文件的复制和转移。
Channel简介
在前一篇文章中,我们通过JDK1.8的官网了解到了 Channe的接口在java.nio.channel包下面,表示IO源与目标打开的连接,主要与缓冲区进行交互。
Channel接口已知的实现类
其中主要的实现类如下:
类名 | 功能 |
---|---|
FileChannel | 用于读取,写入,映射和操作文件的通道 |
DatagramChannel | 通过UDP读写网络中的数据通道 |
SocketChannel | 通过TCP读写网络中的数据通道 |
ServerSocketChannel | 可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个 SocketChannel。 |
获取通道的方法
通道中数据的传输
相关代码实现
通过文件输入出流获取通道使用非直接缓冲区实现文件的复制
- 目录结构
- 实现代码
@Test
public void test1() {
long start = System.currentTimeMillis();
//首先动态的获取到要复制的文件的路径
String path = TestChannel.class.getResource("/")
.getPath().substring(1)
.replace("target/classes/", "src/main/resources");
//定义文件输入流
FileInputStream fileInputStream = null;
//定义文件输出流
FileOutputStream fileOutputStream = null;
//定义通道
FileChannel inFileChannel = null;
FileChannel outFileChannel = null;
try {
//获取文件流
fileInputStream = new FileInputStream(path + "/text.txt");
fileOutputStream = new FileOutputStream(path + "/text1.txt");
//获取通道
inFileChannel = fileInputStream.getChannel();
outFileChannel = fileOutputStream.getChannel();
//指定缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
while (inFileChannel.read(byteBuffer) != -1) {
byteBuffer.flip(); //切换读取数据的模式
//④将缓冲区中的数据写入通道中
outFileChannel.write(byteBuffer);
byteBuffer.clear(); //清空缓冲区
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流和通道
if (outFileChannel != null) {
try {
outFileChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inFileChannel != null) {
try {
inFileChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
long end = System.currentTimeMillis();
System.out.println("耗费时间为:" + (end - start));
}
- 运行结果
使用直接缓冲区完成文件的复制(内存映射文件)
- 实现代码
//使用直接缓冲区完成文件的复制(内存映射文件)
@Test
public void test2() throws IOException {
long startTime = System.currentTimeMillis();
//首先动态的获取到要复制的文件的路径
String path = TestChannel.class.getResource("/")
.getPath().substring(1)
.replace("target/classes/", "src/main/resources");
//获取通道
FileChannel inChannel = FileChannel.open(Paths.get(path + "/text.txt"), StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get(path + "/text2.txt"), StandardOpenOption.READ,
StandardOpenOption.WRITE, StandardOpenOption.CREATE);
//定义缓冲区
MappedByteBuffer inMappedBuf = inChannel.map(FileChannel.MapMode.READ_ONLY,0,inChannel.size());
MappedByteBuffer outMappedBuf = outChannel.map(FileChannel.MapMode.READ_WRITE,0,inChannel.size());
//直接对缓冲区进行数据的读写操作
byte[] dst = new byte[inMappedBuf.limit()];
inMappedBuf.get(dst);
outMappedBuf.put(dst);
inChannel.close();
outChannel.close();
long endTime = System.currentTimeMillis();
System.out.println("复制时间为:" + (endTime - startTime));
}
- 运行结果
使用通道间的文件传输实现文件复制
- 实现代码
long startTime = System.currentTimeMillis();
//首先动态的获取到要复制的文件的路径
String path = TestChannel.class.getResource("/")
.getPath().substring(1)
.replace("target/classes/", "src/main/resources");
//获取通道
FileChannel inChannel = FileChannel.open(Paths.get(path + "/text.txt"), StandardOpenOption.READ);
FileChannel outChannel1 = FileChannel.open(Paths.get(path + "/text3.txt"), StandardOpenOption.READ,
StandardOpenOption.WRITE, StandardOpenOption.CREATE);
FileChannel outChannel2 = FileChannel.open(Paths.get(path + "/text4.txt"), StandardOpenOption.READ,
StandardOpenOption.WRITE, StandardOpenOption.CREATE);
inChannel.transferTo(0,inChannel.size(),outChannel1);
outChannel2.transferFrom(inChannel,0,inChannel.size());
long endTime = System.currentTimeMillis();
System.out.println("复制时间为:" + (endTime - startTime));
- 运行结果
使用分散和聚集实现文件的复制
- 实现代码
//分散和聚集
@Test
public void test4() throws IOException{
RandomAccessFile raf1 = new RandomAccessFile("1.txt", "rw");
//1. 获取通道
FileChannel channel1 = raf1.getChannel();
//2. 分配指定大小的缓冲区
ByteBuffer buf1 = ByteBuffer.allocate(100);
ByteBuffer buf2 = ByteBuffer.allocate(1024);
//3. 分散读取
ByteBuffer[] bufs = {buf1, buf2};
channel1.read(bufs);
for (ByteBuffer byteBuffer : bufs) {
byteBuffer.flip();
}
System.out.println(new String(bufs[0].array(), 0, bufs[0].limit()));
System.out.println("-----------------");
System.out.println(new String(bufs[1].array(), 0, bufs[1].limit()));
//4. 聚集写入
RandomAccessFile raf2 = new RandomAccessFile("2.txt", "rw");
FileChannel channel2 = raf2.getChannel();
channel2.write(bufs);
}
- 运行结果