仅支持transfer和transferfrom方法
发布网友
发布时间:2023-03-06 10:54
我来回答
共3个回答
热心网友
时间:2023-06-23 07:06
FileChannel中提供了两个方法 transferFrom(ReadableByteChannel src, long position, long count) 和 transferTo(long position, long count, WritableByteChannel target)用于两个通道间的数据传输,通常使用单线程进行传输的时候这两个方法不会出现什么问题, 但是 当我使用多线程方式 进行文件的复制的时候, transferFrom 方法最后传输的总是 count的长度(count是每个线程平均分配处理的长度).
热心网友
时间:2023-06-23 07:06
transferTo()和transferFrom()方法使您可以将一个通道交叉连接到另一个通道,而无需通过中间缓冲区传递数据。
热心网友
时间:2023-06-23 07:07
按照此需求,常规方式,我们使用如下代码来完成:
File file = new File("D:\\test.txt");
Long size = file.length();
byte[] arr = new byte[size.intValue()];
try {
// 1.将test.txt文件内容读取到arr中
FileInputStream fileInputStream = new FileInputStream(file);
fileInputStream.read(arr);
// 2.提供对外服务
Socket socket = new ServerSocket(9999).accept();
// 3.传输到客户端
socket.getOutputStream().write(arr);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
以上是一个最简单版本的实现。
那么从操作系统的角度,以上传输经历了哪些过程呢?
这中间的过程我们可以分为以下几步:
fileInputStream.read方法对应于:
1)第一次复制:read方法调用,用户态切换到内核态。数据从硬盘拷贝到内核缓冲区,基于DMA自动操作,不需要CPU支持
2)第二次复制:从内核缓冲区拷贝到用户缓冲区(也就是byte[] arr中)。read方法返回,用内核态到用户态的转换。
socket.getOutputStream().write(arr)对应于:
3)第三次复制:从用户缓冲区拷贝数据到socket的内核缓冲区。write方法调用,用户态切换到内核态。
4)数据从socket内核缓冲区,使用DMA拷贝到网络协议引擎。write方法返回,内核态切换到用户态。
从上面的过程我们可以发现,数据发生了四次拷贝,四次上下文切换。
那么还有没有优化方式呢?答案是肯定的,我们接着往下看。
2.mmap优化
mmap通过内存映射,将文件直接映射到内存中。此时,用户空间和内核空间可以共享这段内存空间的内容。用户对内存内容的修改可以直接反馈到磁盘文件上。
FileChannel提供了map方法来实现mmap功能
File file = new File("D:\\test.txt");
Long size = file.length();
byte[] arr = new byte[size.intValue()];
try {
// 1.将test.txt文件内容读取到arr中
RandomAccessFile raFile = new RandomAccessFile(file, "rwd");
FileChannel channel = raFile.getChannel();
MappedByteBuffer mappedByteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, size);
// 2.提供对外服务
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(9999));
serverSocketChannel.configureBlocking(false);
while(true){
SocketChannel socketChannel =
serverSocketChannel.accept();
if(socketChannel != null){
// 3.传输到客户端
socketChannel.write(mappedByteBuffer);
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
我们直接将file的内容映射到mappedByteBuffer,然后直接将mappedByteBuffer的内容传递出去