NIO之通道(Channel)的原理与获取以及数据传输与内存映射文件详解编程语言

通道(Channel)

  由java.nio.channels包定义的,Channel表示IO源与目标打开的连接,Channel类似于传统的“流”,只不过Channel本身不能直接访问数据,Channel只能与Buffer进行交互。通道主要用于传输数据,从缓冲区的一侧传到另一侧的实体(如文件、套接字…),反之亦然;通道是访问IO服务的导管,通过通道,我们可以以最小的开销来访问操作系统的I/O服务;顺便说下,缓冲区是通道内部发送数据和接收数据的端点。

  在标准的IO当中,都是基于字节流/字符流进行操作的,而在NIO中则是是基于Channel和Buffer进行操作,其中的Channel的虽然模拟了流的概念,实则大不相同。

区别 Stream Channel
支持异步 不支持 支持
是否可双向传输数据 不能,只能单向 可以,既可以从通道读取数据,也可以向通道写入数据
是否结合Buffer使用 必须结合Buffer使用
性能 较低 较高

传统与革新

传统的数据流:
CPU处理IO,性能损耗太大
改为:
内存和IO接口之间加了 DMA(直接存储器),DMA向CPU申请权限,IO的操作全部由DMA管理。CPU不要干预。
若有大量的IO请求,会造成DMA的走线过多,则也会影响性能。
则改DMA为Channel,Channel为完全独立的单元,不需要向CPU申请权限,专门用于IO。
 

早一代IO操作是由CPU负责IO接口

NIO之通道(Channel)的原理与获取以及数据传输与内存映射文件详解编程语言

新一代DMA授权处理IO接口

NIO之通道(Channel)的原理与获取以及数据传输与内存映射文件详解编程语言

通道(Channel)模式

NIO之通道(Channel)的原理与获取以及数据传输与内存映射文件详解编程语言

代码示例

  1 package com.expgiga.NIO; 
  2  
  3 import java.io.FileInputStream; 
  4 import java.io.FileOutputStream; 
  5 import java.io.IOException; 
  6 import java.nio.ByteBuffer; 
  7 import java.nio.MappedByteBuffer; 
  8 import java.nio.channels.FileChannel; 
  9 import java.nio.file.Paths; 
 10 import java.nio.file.StandardOpenOption; 
 11  
 12 /** 
 13  * 一、Channel:用于源节点与目标节点之间的连接。在Java NIO中,负责缓冲区中数据传输,Channel本身不存储数据,因此需要配合缓冲区进行传输。 
 14  * 
 15  * 二、Channel的实现类: 
 16  *     java.nio.channels.Channel 接口: 
 17  *     |-- FileChannel 
 18  *     |-- SocketChannel 
 19  *     |-- ServerSocketChannel 
 20  *     |-- DatagramChannel 
 21  * 
 22  * 三、获取通道Channel 
 23  * 1.Java针对支持通道的类提供了getChannel()方法 
 24  *   本地IO 
 25  *   FileInputStream/FileOutputStream 
 26  *   RandomAccessFile 
 27  * 
 28  *   网络IO: 
 29  *   Socket 
 30  *   ServerSocket 
 31  *   DatagramSocket 
 32  * 
 33  * 2.在jdk1.7中的NIO.2针对各个通道提供了静态方法open() 
 34  * 
 35  * 3.在jdk1.7中的NIO.2的Files工具类的newByteChannel() 
 36  * 
 37  * 四、通道之间的数据传输 
 38  * transferFrom() 
 39  * transferTo() 
 40  * 
 41  */ 
 42 public class TestChannel { 
 43  
 44     public static void main(String[] args) throws IOException { 
 45  
 46         /* 
 47          * 1.利用通道完成文件的复制(非直接缓冲区) 
 48          */ 
 49         FileInputStream fis = null; 
 50         FileOutputStream fos = null; 
 51  
 52         FileChannel inChannel = null; 
 53         FileChannel outChannel = null; 
 54  
 55         try { 
 56             fis = new FileInputStream("1.jpg"); 
 57             fos = new FileOutputStream("2.jpg"); 
 58             //1.获取通道 
 59             inChannel = fis.getChannel(); 
 60             outChannel = fos.getChannel(); 
 61  
 62             //2.分配指定大小的缓冲区 
 63             ByteBuffer buffer = ByteBuffer.allocate(1024); 
 64  
 65             //3.将通道中的数据缓冲区中 
 66             while (inChannel.read(buffer) != -1) { 
 67  
 68                 buffer.flip();//切换成都数据模式 
 69  
 70                 //4.将缓冲区中的数据写入通道中 
 71                 outChannel.write(buffer); 
 72                 buffer.clear();//清空缓冲区 
 73             } 
 74         } catch (Exception e) { 
 75             e.printStackTrace(); 
 76         } finally { 
 77             if (outChannel != null) { 
 78                 try { 
 79                     outChannel.close(); 
 80                 } catch (IOException e) { 
 81                     e.printStackTrace(); 
 82                 } 
 83             } 
 84  
 85             if (inChannel != null) { 
 86                 try { 
 87                     inChannel.close(); 
 88                 } catch (IOException e) { 
 89                     e.printStackTrace(); 
 90                 } 
 91             } 
 92  
 93             if (fis != null) { 
 94                 try { 
 95                     fis.close(); 
 96                 } catch (IOException e) { 
 97                     e.printStackTrace(); 
 98                 } 
 99             } 
100  
101             if (fos != null) { 
102                 try { 
103                     fos.close(); 
104                 } catch (IOException e) { 
105                     e.printStackTrace(); 
106                 } 
107             } 
108         } 
109  
110  
111         /* 
112          * 2.利用(直接缓冲区)通道完成文件的复制(内存映射文件的方式) 
113          */ 
114  
115         long start = System.currentTimeMillis(); 
116         FileChannel inChannel2 = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ); 
117         FileChannel outChannel2 = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE); 
118  
119         //内存映射文件 
120         MappedByteBuffer inMappedBuf = inChannel2.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size()); 
121         MappedByteBuffer outMappedBuf = outChannel2.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size()); 
122  
123         //直接对缓冲区进行数据读写操作 
124         byte[] dst = new byte[inMappedBuf.limit()]; 
125         inMappedBuf.get(dst); 
126         outMappedBuf.put(dst); 
127  
128         inChannel2.close(); 
129         outChannel2.close(); 
130  
131         long end = System.currentTimeMillis(); 
132         System.out.println("耗费的时间为:" + (end - start)); 
133  
134         /* 
135          * 通道之间的数据传输(直接缓冲区) 
136          */ 
137         FileChannel inChannel3 = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ); 
138         FileChannel outChannel3 = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE); 
139  
140         inChannel3.transferTo(0, inChannel3.size(), outChannel3); 
141         //等价于 
142 //        outChannel3.transferFrom(inChannel3, 0, inChannel3.size()); 
143  
144         inChannel3.close(); 
145         outChannel3.close(); 
146     } 
147 }

 

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/15744.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论