浅谈NIO(二)
通道(Channel)的原理
Channel表示IO源与目标打开的连接,由java.nio.channels包定义的。Channel 类似于传统的“流”。但是Channel 本身并不能直接访问数据,只负责传输, Buffer 负责存储。Channel与Buffer进行交互。
java.nio.channels.Channel 接口:
|--FileChannel
|--SocketChannel
|--ServerSocketChannel
|--DatagramChannel
获取通道
1,Java 针对支持通道的类提供了 getChannel() 方法
本地 IO:
FileInputStream/FileOutputStream
RandomAccessFile
网络IO:
Socket
ServerSocket
DatagramSocket
2,在JDK1.7中的NIO.2针对各个通过提供了静态方法open()
3,在JDK1.7中的NIO.2的Files工具类的newByteChannel()
4,Channles工具类中提供了静态方法newChannel()。
直接缓冲区与非直接缓冲区别(图片来自百度)
非直接缓冲区:通过 allocate() 方法分配缓冲区,将缓冲区建立在 JVM 的内存中
当使用非直接缓冲区的时候,我们读取数据是从物理磁盘开始然后在物理空间(左)中保存一份,然后再copy一份到JVM空间(右),写数据的时候也是同理,这样就是效率不高。
直接缓冲区:通过 allocateDirect() 方法分配直接缓冲区,将缓冲区建立在物理内存中。可以提高效率
使用直接缓存区的时候读写是通过物理内存的,不经过JVM,但是这样就会产生安全问题,当我们清空内存的时候数据也就没了
代码实现
public class Demo2 { public static void main(String[] args) throws Exception{ //时间的API long statTime=System.currentTimeMillis(); // 读入流 FileInputStream fileInputStream = new FileInputStream ("D:/进击的巨人.mp4"); // 写入流 FileOutputStream fileOutputStream = new FileOutputStream ("E:/进击的巨人.mp4"); // 创建通道 FileChannel inChannel = fileInputStream.getChannel(); FileChannel outChannel = fileOutputStream.getChannel(); // 分配指定大小缓冲区 ByteBuffer buf = ByteBuffer.allocate(1024); while (inChannel.read(buf) != -1) { // 开启读取模式 buf.flip(); // 将数据写入到通道中 outChannel.write(buf); //每次写入后都要重置一下界限 buf.clear(); } // 关闭通道 、关闭连接 inChannel.close(); outChannel.close(); fileOutputStream.close(); fileInputStream.close(); long endTime=System.currentTimeMillis(); System.out.println("操作非直接缓冲区耗时时间:"+(endTime-statTime)); } }
public class Demo3 { public static void main(String[] args) throws Exception{ long statTime=System.currentTimeMillis(); //创建管道,参数为地址+权限 FileChannel inChannel= FileChannel.open(Paths.get("D:/进击的巨人.mp4"), StandardOpenOption.READ); //因为下面outMappedByte是读写权限,所以这里也要有读写权限 FileChannel outChannel= FileChannel.open(Paths.get("E:/进击的巨人.mp4"), StandardOpenOption.READ,StandardOpenOption.WRITE, StandardOpenOption.CREATE); //定义映射文件 MappedByteBuffer inMappedByte = inChannel.map (FileChannel.MapMode.READ_ONLY,0, inChannel.size()); MappedByteBuffer outMappedByte = outChannel.map (FileChannel.MapMode.READ_WRITE,0, inChannel.size()); //直接对缓冲区操作 byte[] dsf=new byte[inMappedByte.limit()]; inMappedByte.get(dsf); outMappedByte.put(dsf); inChannel.close(); outChannel.close(); long endTime=System.currentTimeMillis(); System.out.println("操作直接缓冲区耗时时间:"+(endTime-statTime)); } }
(这些代码基本都是固定的)