什么是零拷贝?
咱们首先来认识一下传统的I/O操做。
假如说用户进程如今要把一个文件复制到另外一个地方。
那么用户程序必须先把这个文件读入内存,而后再把内存里的数据写入另外一个文件。
不过文件读入内存也不是直接读入用户进程的内存,而是先读入操做系统内核的内存,而后再从操做系统内核的内存区读到用户进程的内存。
与之对应的是,写文件也不是直接写到磁盘上的文件,而是用户进程先把本身内存的数据传到操做系统内核的内存,而后再从操做系统内核的内存区写到磁盘。而这其中涉及到诸多的系统调用。
所以看上去简单的操做至少要分为四部
1磁盘文件读入操做系统
2操做系统读到用户进程
3用户进程写到操做系统
4操做系统写入磁盘文件java
零拷贝和传统I/O有和不一样?
零拷贝就是指,传输一个文件的时候,不须要把文件读到用户进程再处理,而是直接把文件读到操做系统一个内存区,而后再移动到操做系统的另外一个内存区,最后写入文件。
这样一来,步骤变成这样:
1磁盘文件读入操做系统
2操做系统把数据写入操做系统另外一个区域
3操做系统写入磁盘文件
虽然只少了一步,可是这里不只减小了数据移动的时间损耗,并且减小了系统调用的次数,所以大大缩短了时间。
更加详细的解释请看https://blog.csdn.net/u010530...编程
java里如何实现零拷贝呢?
这就要提及java nio中的FileChannel.transferTo()方法了,该方法是把FileChannel中的数据利用零靠的技术转移到另外一个channel。这另外一个channel每每是FileChannel,不过SocketChannel也是能够的:)。
简单实现(静态下载文件,不能根据用户指令来更改下载的文件。)
代码以下:
单线程版本:服务器
package qiuqi.filedownloadtest; import java.io.FileInputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.*; import java.util.Iterator; public class FileServer { public static void main(String[] args) throws IOException { startServer(); } public static void startServer() throws IOException { ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.bind(new InetSocketAddress(9999)); serverSocketChannel.configureBlocking(false); Selector selector = Selector.open(); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); while (selector.select() > 0) { Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); iterator.remove(); if(key.isAcceptable()) { SocketChannel socketChannel = serverSocketChannel.accept(); try (FileInputStream in = new FileInputStream("C:\\Users\\dell\\Desktop\\ZOL手机数据(1).rar")){ long size = in.available(); long num = 0; long begin = 0; while ( (num = in.getChannel().transferTo(begin,size,socketChannel))!=0) { size-=num; begin += num; } socketChannel.close(); } catch (IOException e){e.printStackTrace();} } } } } }
多线程版本:多线程
package qiuqi.filedownloadtest; import java.io.FileInputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.*; import java.util.Iterator; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class FileServer { static ExecutorService threadpool = Executors.newCachedThreadPool(); public static void main(String[] args) throws IOException { startServer(); } public static void startServer() throws IOException { ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.bind(new InetSocketAddress(9999)); serverSocketChannel.configureBlocking(false); Selector selector = Selector.open(); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); while (selector.select() > 0) { Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); iterator.remove(); if(key.isAcceptable()) { SocketChannel socketChannel = serverSocketChannel.accept(); threadpool.execute(new Runnable() { @Override public void run() { try (FileInputStream in = new FileInputStream("C:\\Users\\dell\\Desktop\\ZOL手机数据(1).rar")){ long size = in.available(); long num = 0; long begin = 0; while ( (num = in.getChannel().transferTo(begin,size,socketChannel))!=0) { size-=num; begin += num; } socketChannel.close(); } catch (IOException e){e.printStackTrace();} } }); } } } } }
代码就不讲解了。若是学过java nio,那么理解上面的程序垂手可得。
若是不熟悉java nio的服务器编程那么请先学习再来观看。socket
最后我想说,java NIO真的是NEW IO即新的IO,而不是NonBlocking IO即非阻塞IO。由于在这套体系里,不单单提供了非阻塞的编程模型,并且提供了相似零拷贝,内存映射这样的新技术(对于操做系统来讲早就有了)。ide