java编程入门零基础 (java nio)

Channel(通道)

Java NIO的通道类似流,但又有些不同:

既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的通道可以异步地读写

通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。

javanio攻略,java编程入门题讲解

Channel的实现

这些是Java NIO中最重要的通道的实现:

  • FileChannel: 从文件中读写数据。
  • DatagramChannel : 能通过UDP读写网络中的数据。
  • SocketChannel: 能通过TCP读写网络中的数据。
  • ServerSocketChannel :可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。

Buffer(缓冲区)

缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。

Buffer(缓冲区)的主要属性

属性功能capacity容量position缓冲区当前位置指针,最大可为capacity – 1limit缓冲区最大读取和写入限制

buffer属性示意图:

javanio攻略,java编程入门题讲解

上图展示了写模式和读模式下,以上属性的示意图,写模式下,limit和capacity是一样的,这表示你能写入的最大容量数据,读模式下,limit会和position一样,表示你能读到写入的全部数据

Buffer(缓冲区)的主要分类

  • ByteBuffer
  • MappedByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer

其实以上基本上为了接收不同的数据类型而对应的,只有一个特殊的MappedByteBuffer,本次先不学习它,后续再去了解它。

五、实战

我们主要以理解上面介绍的概念为目的实现一个简单的NIO编程,读取文件夹内的文件,然后输出到控制台。

  1. public
  2. static
  3. void
  4. testNio
  5. (){
  6. try
  7. {
  8. RandomAccessFile
  9. rdf
  10. =
  11. new
  12. RandomAccessFile
  13. (
  14. "E:\\nio\\niotest.txt"
  15. ,
  16. "rw"
  17. );
  18. //利用channel中的FileChannel来实现文件的读取
  19. FileChannel
  20. inChannel
  21. =
  22. rdf
  23. .
  24. getChannel
  25. ();
  26. //设置缓冲区容量为10
  27. ByteBuffer
  28. buf
  29. =
  30. ByteBuffer
  31. .
  32. allocate
  33. (
  34. 10
  35. );
  36. //从通道中读取数据到缓冲区,返回读取的字节数量
  37. int
  38. byteRead
  39. =
  40. inChannel
  41. .
  42. read
  43. (
  44. buf
  45. );
  46. //数量为-1表示读取完毕。
  47. while
  48. (
  49. byteRead
  50. !=-
  51. 1
  52. ){
  53. //切换模式为读模式,其实就是把postion位置设置为0,可以从0开始读取
  54. buf
  55. .
  56. flip
  57. ();
  58. //如果缓冲区还有数据
  59. while
  60. (
  61. buf
  62. .
  63. hasRemaining
  64. ()){
  65. //输出一个字符
  66. System
  67. .
  68. out
  69. .
  70. print
  71. ((
  72. char
  73. )
  74. buf
  75. .
  76. get
  77. ());
  78. }
  79. //数据读完后清空缓冲区
  80. buf
  81. .
  82. clear
  83. ();
  84. //继续把通道内剩余数据写入缓冲区
  85. byteRead
  86. =
  87. inChannel
  88. .
  89. read
  90. (
  91. buf
  92. );
  93. }
  94. //关闭通道
  95. rdf
  96. .
  97. close
  98. ();
  99. }
  100. catch
  101. (
  102. FileNotFoundException
  103. e
  104. )
  105. {
  106. e
  107. .
  108. printStackTrace
  109. ();
  110. }
  111. catch
  112. (
  113. IOException
  114. e
  115. )
  116. {
  117. e
  118. .
  119. printStackTrace
  120. ();
  121. }
  122. }

在磁盘中niotest.txt的内容是hello world,我们看看运行结果是不是hello world。

javanio攻略,java编程入门题讲解

结果和预期一样,我们完成了NIO编程输出磁盘文件内容,其实上面代码中,我第一印象有疑问的地方就是 buf.flip(),其他只要用过IO的应该都能理解,既然不能理解我们就先调试下,注释掉该段内容,看看输出结果如何。

javanio攻略,java编程入门题讲解

注释掉 buf.flip() 后,输出结果果真不对了,那究竟是为啥呢?

javanio攻略,java编程入门题讲解

上图是第一个循环,我们可以看到缓冲区的position=10,limit=10,cap=10。调用 buf.hasRemaining()

为false,所以buffer第一次没有输出任何东西。看看第二次循环

javanio攻略,java编程入门题讲解

其实这整个循环可以解析步骤如下:

  • buffer读取了10字节内容,内容就是:hello worl。
  • buf.hasRemaining() 判断为false,直接清空buffer(直接把position复位为0,可以直接覆盖内容),读取剩下内容。
  • 最后只剩下一个字符 d 读取,这个时候读取完后,buffer内容如下:dello worl。
  • 最后输出因为从postion=1位置输出,所以输出:ello worl。

根据以上解析,我们发现注释了buf.flip()后,position位置写入是什么位置,读出就是什么位置,所以,该方法应该就是把position赋值为0,从开始读取。解读源码也证实了我的猜想,源码如下:

  1. public
  2. final
  3. Buffer
  4. flip
  5. ()
  6. {
  7. limit
  8. =
  9. position
  10. ;
  11. position
  12. =
  13. 0
  14. ;
  15. mark
  16. =
  17. -
  18. 1
  19. ;
  20. return
  21. this
  22. ;
  23. }

推荐阅读

  • 【JVM】类加载、连接和初始化过程
  • 2018全套学习视频资源已经整理好了!免费分享!
  • 【资源分享】Docker核心技术视频教程
  • 【资源分享】蚂蚁课堂2期无加密-Java视频教程
  • Java日志体系详细总结
  • 【资源分享】Spring Cloud微服务实战视频课程
  • 并发编程之ThreadLocal关键字
  • 详解BlockingQueue
  • Springmvc源码解析总结
  • myBatis 体系结构源码解读

微信:Yuanping1510

本公众号会不定期给大家发福利,包括学习资源等,敬请期待吧!

推送内容如果现在工作用不上,可以先转发朋友圈或收藏,用的时候方便找。

另外欢迎关注公众号或添加微信好友,互相学习交流。