Java NIO 之 Channel
一、什么是Channel
Channel用于源节点(例如磁盘)与目的节点的连接,它可以进行读取,写入,映射和读/写文件等操作。
在Java NIO中负责缓冲区中数据的传输。Channel本省不存储数据,因此需要配合缓冲区进行传输。(个人理解其实就是相当于保存两通信地间的上写问和进行读写操作,相当于邮局)
二、通道的主要实现类
java.nio.channels.Channel接口:
- FileChannel(本地)
- SocketChannel(TCP)
- ServerSocketChannel(TCP)
- DatagramChannel(UDP)
三、获取通道的方式
- Java 针对支持通道的类提供了getChannel()方法
- FileInputStream/FileOutputStream(本地IO)
- RandomAccessFile(本地IO)
- Socket(网络IO)
- ServerSocket(网络IO)
- DatagramSocket(网络IO)
- 在JDK1.7中NIO.2针对各个通道提供了静态方法open()
- 在JDK1.7中NIO.2的Files工具类的newByteChannel()
四、通道之间的数据传输
-
transferFrom()
-
transferTo()
@Test public void test3() throws IOException { FileChannel inChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.READ); FileChannel outchannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);
1inChannel.transferTo(0,inChannel.size(),outchannel); 2//outchannel.transferFrom(inChannel, 0,inChannel.size()); 3inChannel.close(); 4outchannel.close();}
其他两种两种传输方式
-
使用直接缓冲区完成文件的复制(内存映射文件)
//实验证明如果传大型文件内存会出现大量占用,如果GC不对内存进行回收,无法确定OS何时把数据写入磁盘 @Test public void test2() throws IOException { FileChannel inChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.READ); FileChannel outchannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);
1//内存映射文件 2MappedByteBuffer inMappedBuf = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size()); 3MappedByteBuffer outMappedBuf = outchannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size()); 4 5//直接对缓存区进行数据的读写操作 6byte[] dst = new byte[inMappedBuf.limit()]; 7inMappedBuf.get(dst); 8outMappedBuf.put(dst);}
-
利用通道完成文件的复制(非直接缓冲区)
@Test public void test1(){ String path = this.getClass().getClassLoader().getResource("1.jpg").getPath();
1FileInputStream fis = null; 2FileOutputStream fos = null; 3 4FileChannel fisChannel = null; 5FileChannel fosChannel = null; 6try { 7 fis = new FileInputStream(path); 8 fos = new FileOutputStream("src/main/resources/2.jpg"); 9 10 //获取通道 11 fisChannel = fis.getChannel(); 12 fosChannel = fos.getChannel(); 13 14 //二、分配指定大小的缓冲区 15 ByteBuffer buf = ByteBuffer.allocate(1024); 16 17 //三、将通道中的数据存入缓冲区中 18 while(fisChannel.read(buf) != -1){ 19 buf.flip(); //切换读取数据的模式 20 //四、将缓冲区的数据写入通道中 21 fosChannel.write(buf); 22 buf.clear(); 23 } 24} catch (IOException e) { 25 e.printStackTrace(); 26}finally { 27 try { 28 fis.close(); 29 } catch (IOException e) { 30 e.printStackTrace(); 31 } 32 try { 33 fos.close(); 34 } catch (IOException e) { 35 e.printStackTrace(); 36 } 37 38 try { 39 fis.close(); 40 } catch (IOException e) { 41 e.printStackTrace(); 42 } 43 try { 44 fos.close(); 45 } catch (IOException e) { 46 e.printStackTrace(); 47 } 48}}
分散(Scatter)与聚集(Gather)
- 分散读取(Scattering Reads): 将通道中的数据分散到多个缓冲区中
- 聚集写入(Gathering Writes):将多个缓冲区中的数据聚集到通道中