Java NIO之Channel

妖狐艹你老母 2022-09-25 00:28 216阅读 0赞

Java NIO之Channel


介绍

定义

  1. Channel(管道):A channel represents an open connection to an entity such as a hardware device, a file, a network socket,
  2. or a program component that is capable of performing one or more distinct I/O operations, for example reading or writing.
  3. 管道可以将其理解为一条连接,可以通过这条连接传输数据。

  1. java nio数据传输介质是管道,就像java io中数据传输介质是流一样。不过io中的流是分方向的输入流和输出流,
  2. 但是nio的管道是双向的既可以输出数据也可以读取数据。当然管道都是基于Buffer对象读取和写入数据的。
  3. java nio借助ChannelSelector实现单线程的多路复用IO.在聊天服务器中会使用到这种技术。

管道传输数据示意图
channel 管道传输数据示意图


Channel实现

  1. Channel接口的实现有:
  2. FileChannel(操作文件相关)
  3. SocketChannel(TCP通信模型客户端Channel)
  4. ServerSocketChannel(TCP通信服务器端Channel)
  5. DatagramChannel(UDP数据报Channel)
  6. 备注:以下的学习时基于FileChannel来实现和学习的,其它几个Channel实现在网络高级编程中会使用到。

Channel接口

  1. Channel接口就只定义了两个方法isOpen()和close()方法。
  2. /**
  3. * 管道表示和磁盘、文件、网络套接字或程序组件的一条连接,它可以用来执行IO操作比如读取数据或写入数据。
  4. *
  5. * A channel represents an open connection to an entity such as a hardware
  6. * device, a file, a network socket, or a program component that is capable of
  7. * performing one or more distinct I/O operations, for example reading or
  8. * writing.
  9. *
  10. * Channels are, in general, intended to be safe for multithreaded access
  11. * as described in the specifications of the interfaces and classes that extend
  12. * and implement this interface.
  13. */
  14. public interface Channel extends Closeable {
  15. /**
  16. * Tells whether or not this channel is open. </p>
  17. */
  18. public boolean isOpen();
  19. /**
  20. * Closes this channel.
  21. */
  22. public void close() throws IOException;
  23. }
  24. jdk nio隐藏细节太多了,如果真要看源码最好还是看openjdk的源码

FileChannel文件管道应用

  1. FileChannel是一个抽象类,可以通过以下方法获得其实例对象
  2. FileInputStream.getChannel()
  3. FileOutputStream.getChannel()
  4. RandomAccessFile.getChannel()

FileChannel核心方法

  1. /**
  2. * A channel for reading, writing, mapping, and manipulating a file.
  3. */
  4. public abstract class FileChannel
  5. extends AbstractInterruptibleChannel
  6. implements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannel
  7. {
  8. // -- Channel operations --
  9. /**
  10. * Reads a sequence of bytes from this channel into the given buffer.
  11. *
  12. * Bytes are read starting at this channel's current file position, and
  13. * then the file position is updated with the number of bytes actually
  14. * read. Otherwise this method behaves exactly as specified in the
  15. * ReadableByteChannel interface.
  16. */
  17. public abstract int read(ByteBuffer dst) throws IOException;
  18. /**
  19. * Writes a sequence of bytes to this channel from the given buffer.
  20. *
  21. * Bytes are written starting at this channel's current file position
  22. * unless the channel is in append mode, in which case the position is
  23. * first advanced to the end of the file. The file is grown, if necessary,
  24. * to accommodate the written bytes, and then the file position is updated
  25. * with the number of bytes actually written. Otherwise this method
  26. * behaves exactly as specified by the WritableByteChannel
  27. * interface.
  28. */
  29. public abstract int write(ByteBuffer src) throws IOException;
  30. // -- Other operations --
  31. /**
  32. * Returns this channel's file position.
  33. */
  34. public abstract long position() throws IOException;
  35. /**
  36. * Sets this channel's file position.
  37. */
  38. public abstract FileChannel position(long newPosition) throws IOException;
  39. /**
  40. * Returns the current size of this channel's file.
  41. */
  42. public abstract long size() throws IOException;
  43. /**
  44. * Truncates this channel's file to the given size.
  45. *
  46. * If the given size is less than the file's current size then the file
  47. * is truncated, discarding any bytes beyond the new end of the file. If
  48. * the given size is greater than or equal to the file's current size then
  49. * the file is not modified. In either case, if this channel's file
  50. * position is greater than the given size then it is set to that size.
  51. *
  52. */
  53. public abstract FileChannel truncate(long size) throws IOException;
  54. /**
  55. * Transfers bytes from this channel's file to the given writable byte
  56. * channel.
  57. */
  58. public abstract long transferTo(long position, long count,
  59. WritableByteChannel target)
  60. throws IOException;
  61. /**
  62. * Transfers bytes into this channel's file from the given readable byte
  63. * channel.
  64. */
  65. public abstract long transferFrom(ReadableByteChannel src,
  66. long position, long count)
  67. throws IOException;
  68. /**
  69. * Reads a sequence of bytes from this channel into the given buffer,
  70. * starting at the given file position.
  71. */
  72. public abstract int read(ByteBuffer dst, long position) throws IOException;
  73. /**
  74. * Writes a sequence of bytes to this channel from the given buffer,
  75. * starting at the given file position.
  76. */
  77. public abstract int write(ByteBuffer src, long position) throws IOException;
  78. // -- Memory-mapped buffers --
  79. /**
  80. * Maps a region of this channel's file directly into memory.
  81. * 具体参考源码
  82. */
  83. public abstract MappedByteBuffer map(MapMode mode,
  84. long position, long size)
  85. throws IOException;
  86. // -- Locks --
  87. /**
  88. * Acquires an exclusive lock on this channel's file.
  89. *
  90. * An invocation of this method of the form fc.lock() behaves
  91. * in exactly the same way as the invocation
  92. */
  93. public final FileLock lock() throws IOException {
  94. return lock(0L, Long.MAX_VALUE, false);
  95. }
  96. /**
  97. * Attempts to acquire an exclusive lock on this channel's file.
  98. *
  99. * An invocation of this method of the form fc.tryLock()
  100. * behaves in exactly the same way as the invocation
  101. */
  102. public final FileLock tryLock() throws IOException {
  103. return tryLock(0L, Long.MAX_VALUE, false);
  104. }
  105. }
  106. FileChannelpositionBufferposition属性是不同的意思,FileChannelposition指的是文件指针位置,
  107. Bufferposition指的是子节数组中下标位置。

FileChannel读写数据分析

  1. ByteBuffer buffer = ByteBuffer.allocate(10);
  2. buffer.put("hello".getBytes());
  3. //从Buffer对象中读取数据时,要先调用flip方法
  4. buffer.flip();
  5. fileChannel.write(buffer);
  6. 备注:因为调用write(buffer)写入数据到管道中时,只能读取Buffer对象中positionlimit之间的数据,
  7. 如果不调用flip方法的话,读取到的Buffer数据可能就是错误的或0
  8. //向Buffer对象中写入数据时,要先调用clear()方法。
  9. buffer.clear();
  10. fileChannel.read(buffer);
  11. 备注:因为调用read(buffer)从管道中读取数据到管道时,如果不先调用clear方法,
  12. 那么Buffer对象就不一定是从position0开始写入数据了,就会导致写入数据到Buffer对象是错误的。
  13. 备注:重点还是在于Buffer对象的那几个变量值,即positionlimitcapacity。最关键的是positionlimit,因为容量初始化之后通常不会变的。

FileChannel的文件拷贝

FileChannel自带的拷贝方法

  1. //nio中Channle 自带提供的拷贝方法
  2. public void testCopyFile2() throws Exception {
  3. // 源文件
  4. FileInputStream inputStream = new FileInputStream(new File("e:/nio/test.jpg"));
  5. // 目标文件
  6. FileOutputStream outputStream = new FileOutputStream(new File("e:/nio/copy.jpg"));
  7. // 获得源文件的通道
  8. FileChannel inChannel = inputStream.getChannel();
  9. // 获得目标文件的通道
  10. FileChannel outChannel = outputStream.getChannel();
  11. // nio自带的考本文件方法
  12. //1、transferFrom(ReadableByteChannel src,long position, long count)
  13. outChannel.transferFrom(inChannel, 0, inChannel.size());
  14. //2、transferTo(long position, long count,WritableByteChannel target)
  15. inChannel.transferTo(0, inChannel.size(), outChannel);
  16. //备注这两个方法是等效的,只是要注意文件读写模式。
  17. //关闭资源 ...
  18. }

基于FileChannel和ByteBuffer实现拷贝

  1. //基于ByteBuffer和FileChannel的文件拷贝
  2. public void testCopyFile() throws Exception {
  3. // 源文件
  4. FileInputStream inputStream = new FileInputStream(new File("e:/nio/2.jpg"));
  5. // 目标文件
  6. FileOutputStream outputStream = new FileOutputStream(new File("e:/nio/2copy.jpg"));
  7. // 获得源文件的通道
  8. FileChannel inChannel = inputStream.getChannel();
  9. // 获得目标文件的通道
  10. FileChannel outChannel = outputStream.getChannel();
  11. ByteBuffer buffer = ByteBuffer.allocate(10);
  12. boolean flag = true;
  13. while (flag) {
  14. buffer.clear();
  15. // 从管道(和源文件建立的管道)读取数据到buffer对象中
  16. int data = inChannel.read(buffer);
  17. buffer.flip();
  18. if (data == -1) {// 一直读写直到没有数据时退出循环
  19. flag = false;
  20. }
  21. // 从buffer对象中读取数据到管道(通过目标文件建立的管道)
  22. outChannel.write(buffer);
  23. }
  24. //关闭资源
  25. }
  26. 我对ByteBuffer对象的理解,是根据结构化的的子节数组,对现实内存的抽象。
  27. 关于Bufferflip()和clear()方法,我的理解是当从Buffer对象中读取数据时,那么要先调用flip()方法,
  28. 当要向Buffer对象中写入数据时,要先调用clear()方法。

总结

  1. 总结其实学习nio最重要的不是学会它们如何操作,因为步骤性的技术通常是冗长难以记忆的,只要长时间不用就可能会生疏,
  2. 但是原理性的东西是内容量比较少的,所以掌握其最核心原理很重要。

参考

1、http://www.ibm.com/developerworks/cn/education/java/j-nio/section5.html
2、http://ifeve.com/file-channel/
3、http://www.cnblogs.com/dolphin0520/p/3916526.html

发表评论

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

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

相关阅读

    相关 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都分为两个阶段: 等