【Java NIO】之 Channel

た 入场券 2023-02-23 05:16 160阅读 0赞

下面以一个实例介绍 Channel 的各种用法


  1. /** * 一、通道(Channel):用于源节点与目标节点的连接。在 Java NIO 中负责缓冲区中数据的传输。 * Channel 本身不存储数据,因此需要配合缓冲区进行传输。 * * 二、通道的主要实现类 * java.nio.channels.Channel 接口: * |--FileChannel * |--SocketChannel * |--ServerSocketChannel * |--DatagramChannel * * 三、获取通道 * 1. Java 针对支持通道的类提供了 getChannel() 方法 * 本地 IO: * FileInputStream/FileOutputStream * RandomAccessFile * * 网络IO: * Socket * ServerSocket * DatagramSocket * * 2. 在 JDK 1.7 中的 NIO.2 针对各个通道提供了静态方法 open() * 3. 在 JDK 1.7 中的 NIO.2 的 Files 工具类的 newByteChannel() * * 四、通道之间的数据传输 * transferFrom() * transferTo() * * 五、分散(Scatter)与聚集(Gather) * 分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区中 * 聚集写入(Gathering Writes):将多个缓冲区中的数据聚集到通道中 * * 六、字符集:Charset * 编码:字符串 -> 字节数组 * 解码:字节数组 -> 字符串 * */
  2. public class TestChannel {
  3. // 利用通道完成文件的复制(非直接缓冲区)
  4. @Test
  5. public void testFileChannel() {
  6. long start = System.currentTimeMillis();
  7. // 文件输入和输出流
  8. FileInputStream fis = null;
  9. FileOutputStream fos = null;
  10. // 文件通道
  11. FileChannel inChannel = null;
  12. FileChannel outChannel = null;
  13. try {
  14. fis = new FileInputStream("D:/DNF.mp4");
  15. fos = new FileOutputStream("D:/DNF2.mp4");
  16. inChannel = fis.getChannel();
  17. outChannel = fos.getChannel();
  18. // 分配缓冲区
  19. ByteBuffer buffer = ByteBuffer.allocate(1024);
  20. // 从输入通道中读取数据到缓冲区
  21. while (inChannel.read(buffer) != -1) {
  22. // 切换缓冲区为读模式
  23. buffer.flip();
  24. // 把缓冲区数据写入到输出通道中
  25. outChannel.write(buffer);
  26. // 清空缓冲区
  27. buffer.clear();
  28. }
  29. } catch (IOException e) {
  30. e.printStackTrace();
  31. } finally {
  32. // 关闭资源
  33. if (outChannel != null){
  34. try {
  35. outChannel.close();
  36. } catch (IOException e) {
  37. e.printStackTrace();
  38. }
  39. }
  40. if (inChannel != null) {
  41. try {
  42. inChannel.close();
  43. } catch (IOException e) {
  44. e.printStackTrace();
  45. }
  46. }
  47. if (fos != null) {
  48. try {
  49. fos.close();
  50. } catch (IOException e) {
  51. e.printStackTrace();
  52. }
  53. }
  54. if (fis != null) {
  55. try {
  56. fis.close();
  57. } catch (IOException e) {
  58. e.printStackTrace();
  59. }
  60. }
  61. }
  62. long end = System.currentTimeMillis();
  63. System.out.println("耗费时间为:" + (end - start));
  64. }
  65. // 使用直接缓冲区完成文件的复制(内存映射文件)
  66. @Test
  67. public void testFileChannel2() throws IOException {
  68. long start = System.currentTimeMillis();
  69. // 获取文件输入输出通道
  70. FileChannel inChannel = FileChannel.open(Paths.get("D:/DNF.mp4"), StandardOpenOption.READ);
  71. FileChannel outChannel = FileChannel.open(Paths.get("D:/DNF3.mp4"),
  72. StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
  73. // 内存映射文件
  74. MappedByteBuffer inMapBuf = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
  75. MappedByteBuffer outMapBuf = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());
  76. // 直接对缓冲区进行读写操作
  77. byte[] bytes = new byte[inMapBuf.limit()];
  78. inMapBuf.get(bytes);
  79. outMapBuf.put(bytes);
  80. // 关闭通道
  81. inChannel.close();
  82. outChannel.close();
  83. long end = System.currentTimeMillis();
  84. System.out.println("耗费时间为:" + (end - start));
  85. }
  86. // 通道之间的数据传输(直接缓冲区)
  87. @Test
  88. public void testChannelTransfer() throws IOException {
  89. // 获取文件输入输出通道
  90. FileChannel inChannel = FileChannel.open(Paths.get("D:/DNF.mp4"), StandardOpenOption.READ);
  91. FileChannel outChannel = FileChannel.open(Paths.get("D:/DNF4.mp4"),
  92. StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
  93. // inChannel.transferTo(0, inChannel.size(), outChannel);
  94. outChannel.transferFrom(inChannel, 0, inChannel.size());
  95. inChannel.close();
  96. outChannel.close();
  97. }
  98. // 分散读取和聚集写入
  99. @Test
  100. public void testScatterAndGatter() throws IOException {
  101. // 获取通道
  102. RandomAccessFile raf1 = new RandomAccessFile("D:/1.txt", "rw");
  103. FileChannel channelRead = raf1.getChannel();
  104. // 分配缓冲区
  105. ByteBuffer buf1 = ByteBuffer.allocate(100);
  106. ByteBuffer buf2 = ByteBuffer.allocate(1024);
  107. // 分散读取
  108. ByteBuffer[] bufs = { buf1, buf2};
  109. channelRead.read(bufs);
  110. for (ByteBuffer buf : bufs) {
  111. buf.flip();
  112. }
  113. System.out.println(new String(bufs[0].array(), 0, bufs[0].limit()));
  114. System.out.println("----------------");
  115. System.out.println(new String(bufs[1].array(), 0, bufs[1].limit()));
  116. // 聚集写入
  117. RandomAccessFile raf2 = new RandomAccessFile("D:/2.txt", "rw");
  118. FileChannel channelWrite = raf2.getChannel();
  119. channelWrite.write(bufs);
  120. // 关闭资源
  121. channelRead.close();
  122. channelWrite.close();
  123. raf1.close();
  124. raf2.close();
  125. }
  126. // 查看支持的字符集
  127. @Test
  128. public void testCharset() {
  129. SortedMap<String, Charset> charsetMap = Charset.availableCharsets();
  130. Set<Map.Entry<String, Charset>> entrySet = charsetMap.entrySet();
  131. for (Map.Entry<String, Charset> entry : entrySet) {
  132. System.out.println(entry.getKey() + "=" + entry.getValue());
  133. }
  134. }
  135. /** * 使用字符集实现字符的编码和解码 * |-- 字符缓冲区 CharBuffer 编码得到字节缓冲区 ByteBuffer * |-- 字节缓冲区 ByteBuffer 解码得到字符缓冲区 CharBuffer */
  136. @Test
  137. public void testEncodeAndDecode() throws IOException{
  138. // 获取字符集
  139. Charset gbk = Charset.forName("GBK");
  140. // 获取字符集对应的编码器和解码器
  141. CharsetEncoder encoder = gbk.newEncoder();
  142. CharsetDecoder decoder = gbk.newDecoder();
  143. // 构建字符缓冲区
  144. CharBuffer charBuf = CharBuffer.allocate(1024);
  145. charBuf.put("测试字符集编解码");
  146. charBuf.flip();
  147. // 编码
  148. ByteBuffer byteBuf = encoder.encode(charBuf);
  149. System.out.println("编码:");
  150. for (int i = 0; i < byteBuf.limit(); i++) {
  151. System.out.print(byteBuf.get() + " ");
  152. }
  153. // 解码
  154. byteBuf.flip();
  155. CharBuffer charBuf2 = decoder.decode(byteBuf);
  156. System.out.println("\n解码:");
  157. System.out.println(charBuf2.toString());
  158. }
  159. }

发表评论

表情:
评论列表 (有 0 条评论,160人围观)

还没有评论,来说两句吧...

相关阅读

    相关 java nio channel

    Java NIO 通道类似于流,但又有一下不同: 1、既可以从通道中读取数据,也可以写数据到通道中。java .io 中的流是单向性。 2、通道数据读取可以异步。 3、通

    相关 Java NIO Channel

    定义 用于源节点和目标节点之间的连接。nio中负责缓冲区中数据传输,Channel本地并不存储数据,而是配合缓冲区进行数据传输。你可以把它理解成io中的流。 结

    相关 NIOChannel

    1、基本概念 Java NIO中,channel用于数据的传输,类似于传统BIO中的流(IOStream)的概念。 我们都知道,系统的I/O都分为两个阶段: 等