个人随笔
目录
二、实战-通道(Channel)(NIO)
2019-03-12 22:13:30

NIO的第二篇,我这里依然不讲解啥是NIO,直接进入实战环节,进入通道实战

一、通道(Channel)

由java.nio.channels包定义的。Channel表示IO源与目标打开的连接。Channel类似于传统的“流”。只不过,Channel只能与Buffer进行交互,本身不存储数据,主要是配合缓冲区进行传输。

二、通道的主要实现

实现java.nio.channels.Channel 接口

实现 用途
FileChannel 这个是文件传输,一般都是本地文件的读取和写入
SocketChannel TCP
ServerSocketChannel TCP
DatagramChannel UDP

三、获取通道

  1. 1Java针对支持通道的类提供了getChannel()方法
  2. *本地IO操作:FileInputStream/FileOutputStreamRandomAccessFile
  3. *网络IO操作:SocketServerSocketDatagramSocket
  4. 2、在JDK1.7中的NIO.2针对各个通道提供了静态方法open();
  5. 3、在JDK1.7中的NIO.2Files工具类的newByteChannel();

四、通道之间的数据传输

虽然通道不存储数据,但是通道之间可以直接进行数据传输

  1. transferFrom()
  2. transferTo()

五、代码实例

  1. package cn.myforever.nio;
  2. import java.io.FileInputStream;
  3. import java.io.FileOutputStream;
  4. import java.io.IOException;
  5. import java.nio.ByteBuffer;
  6. import java.nio.MappedByteBuffer;
  7. import java.nio.channels.FileChannel;
  8. import java.nio.channels.FileChannel.MapMode;
  9. import java.nio.file.Paths;
  10. import java.nio.file.StandardOpenOption;
  11. import org.junit.Test;
  12. /**
  13. * suibibk.com
  14. */
  15. public class TestChannel {
  16. //1、用通道实现一个文件的复制操作(非直接缓冲区)
  17. @Test
  18. public void test1() {
  19. //获取通道的流
  20. FileInputStream fis = null;
  21. FileOutputStream fos = null;
  22. //获取的通道
  23. FileChannel inChannel = null;
  24. FileChannel outChannel = null;
  25. try {
  26. //获取文件流
  27. fis = new FileInputStream("1.txt");
  28. fos = new FileOutputStream("2.txt");
  29. //通过流获取通道
  30. inChannel = fis.getChannel();
  31. outChannel = fos.getChannel();
  32. //分配指定大小的缓冲区
  33. ByteBuffer buf = ByteBuffer.allocate(1024);
  34. //将通道中的数据存入缓冲区,此事的缓冲区是写模式,按我之前的理解,从通道到缓冲区是从外到里所以用read
  35. while(inChannel.read(buf)!=-1) {
  36. //此时读完后将缓冲区切换为读取数据的模式
  37. buf.flip();
  38. //将缓冲区的数据写入通道中,此时相当于从里到外,用write
  39. outChannel.write(buf);
  40. //清空缓冲区,继续下一次读,其实这里只是把position的位置变为0,并没有真正清空缓冲区,数据是处于被遗忘的状态,此时limit也变成1024
  41. buf.clear();
  42. }
  43. } catch (Exception e) {
  44. e.printStackTrace();
  45. }finally {
  46. if(outChannel!=null) {
  47. try {
  48. outChannel.close();
  49. } catch (IOException e) {
  50. // TODO Auto-generated catch block
  51. e.printStackTrace();
  52. }
  53. }
  54. if(inChannel!=null) {
  55. try {
  56. inChannel.close();
  57. } catch (IOException e) {
  58. // TODO Auto-generated catch block
  59. e.printStackTrace();
  60. }
  61. }
  62. if(fos!=null) {
  63. try {
  64. fos.close();
  65. } catch (IOException e) {
  66. // TODO Auto-generated catch block
  67. e.printStackTrace();
  68. }
  69. }
  70. if(fis!=null) {
  71. try {
  72. fis.close();
  73. } catch (IOException e) {
  74. // TODO Auto-generated catch block
  75. e.printStackTrace();
  76. }
  77. }
  78. }
  79. }
  80. //2、使用直接缓冲区完成文件的复制
  81. @Test
  82. public void test2() {
  83. //这里不用流实现,直接用jdk1.7提供的open方法
  84. FileChannel inChannel =null;
  85. FileChannel outChannel =null;
  86. try {
  87. inChannel = FileChannel.open(Paths.get("1.txt"), StandardOpenOption.READ);
  88. //CREATE_NEW 这个表示存在报错,不存在就创建
  89. outChannel = FileChannel.open(Paths.get("3.txt"), StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE_NEW);
  90. //到这里就可以直接跟例子1一样了,但是我们要用直接缓冲区,所以用map方法将内容映射到屋里内存当中
  91. //内存映射文件(这种方式只有ByteBuffer支持)
  92. MappedByteBuffer inMappedBuf = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
  93. //大小跟inChannel一样;这里是读写,所以上面获取通道的时候也需要是读写功能
  94. MappedByteBuffer outMappedBuf = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());
  95. //这种不用通道了,因为直接在物理内存中,直接操作缓冲区进行数据的读写操作即可
  96. byte[] bytes = new byte[inMappedBuf.limit()];
  97. inMappedBuf.get(bytes);
  98. //写入通道
  99. outMappedBuf.put(bytes);
  100. } catch (IOException e) {
  101. // TODO Auto-generated catch block
  102. e.printStackTrace();
  103. }finally {
  104. if(outChannel!=null) {
  105. try {
  106. outChannel.close();
  107. } catch (IOException e) {
  108. // TODO Auto-generated catch block
  109. e.printStackTrace();
  110. }
  111. }
  112. if(inChannel!=null) {
  113. try {
  114. inChannel.close();
  115. } catch (IOException e) {
  116. // TODO Auto-generated catch block
  117. e.printStackTrace();
  118. }
  119. }
  120. }
  121. }
  122. //3、通道之间的数据传输
  123. @Test
  124. public void test3() {
  125. //这里不用流实现,直接用jdk1.7提供的open方法
  126. FileChannel inChannel =null;
  127. FileChannel outChannel =null;
  128. try {
  129. inChannel = FileChannel.open(Paths.get("1.txt"), StandardOpenOption.READ);
  130. //CREATE_NEW 这个表示存在报错,不存在就创建
  131. outChannel = FileChannel.open(Paths.get("4.txt"), StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE_NEW);
  132. //到这里就可以直接跟例子1一样了,但是我们要用直接缓冲区,所以用map方法将内容映射到屋里内存当中
  133. inChannel.transferTo(0, inChannel.size(), outChannel);
  134. } catch (IOException e) {
  135. // TODO Auto-generated catch block
  136. e.printStackTrace();
  137. }finally {
  138. if(outChannel!=null) {
  139. try {
  140. outChannel.close();
  141. } catch (IOException e) {
  142. // TODO Auto-generated catch block
  143. e.printStackTrace();
  144. }
  145. }
  146. if(inChannel!=null) {
  147. try {
  148. inChannel.close();
  149. } catch (IOException e) {
  150. // TODO Auto-generated catch block
  151. e.printStackTrace();
  152. }
  153. }
  154. }
  155. }
  156. }

结语

通道往往是跟缓冲区一起使用,比如文件通道FileChannel,只要打开通道,就相当于获取了程序跟硬盘之间的连接,然后通过缓冲区Buffer来传输数据,比如是从程序写内容到硬盘,就只需要将缓冲区的数据,写入通道中即可,反之只需要将内容写入缓冲区就是读取数据。

 509

啊!这个可能是世界上最丑的留言输入框功能~


当然,也是最丑的留言列表

有疑问发邮件到 : suibibk@qq.com 侵权立删
Copyright : 个人随笔   备案号 : 粤ICP备18099399号-2