Java NIO 之Buffer

左手的ㄟ右手 2022-09-24 15:17 329阅读 0赞

Java NIO 之Buffer

介绍

  1. 就速度而言CPU>内存>磁盘,而Buffer扮演的就是内存角色。
  2. 为了能够提高IO操作的性能,java定义了一个Buffer对象来表示内存块,其实本质上就是一个字节数组,但是其有更加简便的方法读取和写入数据操作方法。
  3. Java NIO中所有读取和写入数据操作都是基于Buffer完成的,在使用nio过程中请忘记输入流/输出流概念。
  4. java io中流是分方向的输入/输出流,而nio中不管是读取还是写入都是从管道中操作的。
  5. javaBuffer抽象对象有很多其子类对象,除了boolean其余其中基本数据类型都有其对应的XXXBuffer抽象类。
  6. 其中当属ByteBuffer最为重要,因为其可以操作任意数据类型文件,因此我们也对其展开研究和学习。
  7. ByteBuffer对应的实现类有两个,HeapByteBuffer 是基于Java堆的实现,而 DirectByteBuffer 则使用了 unsafe API进行了堆外的实现。

Buffer常用方法

  1. /**
  2. * A container for data of a specific primitive type.
  3. */
  4. public abstract class Buffer {
  5. // Invariants: mark <= position <= limit <= capacity
  6. private int mark = -1;//游标
  7. private int position = 0;//当前位置
  8. private int limit;//上限
  9. private int capacity;//buffer容器容量,capacity通常定义完之后就不会再变化了。
  10. /**
  11. * Returns this buffer's capacity.
  12. */
  13. public final int capacity() {
  14. return capacity;
  15. }
  16. /**
  17. * Returns this buffer's position.
  18. */
  19. public final int position() {
  20. return position;
  21. }
  22. /**
  23. * Returns this buffer's limit.
  24. *
  25. * @return The limit of this buffer
  26. */
  27. public final int limit() {
  28. return limit;
  29. }
  30. /**
  31. * Flips this buffer. The limit is set to the current position and then
  32. * the position is set to zero. If the mark is defined then it is
  33. * discarded.
  34. *
  35. * This method is often used in conjunction with the {@link
  36. * java.nio.ByteBuffer#compact compact} method when transferring data from
  37. * one place to another.
  38. */
  39. public final Buffer flip() {
  40. limit = position;
  41. position = 0;
  42. mark = -1;
  43. return this;
  44. }
  45. /**
  46. * Tells whether there are any elements between the current position and
  47. * the limit.
  48. */
  49. public final boolean hasRemaining() {
  50. return position < limit;
  51. }
  52. /**
  53. * Returns the number of elements between the current position and the
  54. * limit.
  55. */
  56. public final int remaining() {
  57. return limit - position;
  58. }
  59. /**********************************************************************/
  60. /**
  61. * Sets this buffer's position. If the mark is defined and larger than the
  62. * new position then it is discarded.
  63. */
  64. public final Buffer position(int newPosition) {
  65. if ((newPosition > limit) || (newPosition < 0))
  66. throw new IllegalArgumentException();
  67. position = newPosition;
  68. if (mark > position) mark = -1;
  69. return this;
  70. }
  71. /**
  72. * Sets this buffer's limit. If the position is larger than the new limit
  73. * then it is set to the new limit. If the mark is defined and larger than
  74. * the new limit then it is discarded.
  75. */
  76. public final Buffer limit(int newLimit) {
  77. if ((newLimit > capacity) || (newLimit < 0))
  78. throw new IllegalArgumentException();
  79. limit = newLimit;
  80. if (position > limit) position = limit;
  81. if (mark > limit) mark = -1;
  82. return this;
  83. }
  84. /**
  85. * Sets this buffer's mark at its position.
  86. */
  87. public final Buffer mark() {
  88. mark = position;
  89. return this;
  90. }
  91. /**
  92. * Resets this buffer's position to the previously-marked position.
  93. */
  94. public final Buffer reset() {
  95. int m = mark;
  96. if (m < 0)
  97. throw new InvalidMarkException();
  98. position = m;
  99. return this;
  100. }
  101. /**
  102. * Clears this buffer. The position is set to zero, the limit is set to
  103. * the capacity, and the mark is discarded.
  104. */
  105. public final Buffer clear() {
  106. position = 0;
  107. limit = capacity;
  108. mark = -1;
  109. return this;
  110. }
  111. /**
  112. * Rewinds this buffer. The position is set to zero and the mark is
  113. * discarded.
  114. */
  115. public final Buffer rewind() {
  116. position = 0;
  117. mark = -1;
  118. return this;
  119. }
  120. /**
  121. * Returns the number of elements between the current position and the
  122. * limit.
  123. */
  124. public final int remaining() {
  125. return limit - position;
  126. }
  127. /**
  128. * Tells whether or not this buffer is read-only.
  129. */
  130. public abstract boolean isReadOnly();
  131. }

ByteBuffer常用方法

  1. public abstract class ByteBuffer
  2. extends Buffer
  3. implements Comparable<ByteBuffer>
  4. {
  5. // These fields are declared here rather than in Heap-X-Buffer in order to
  6. // reduce the number of virtual method invocations needed to access these
  7. // values, which is especially costly when coding small buffers.
  8. //
  9. final byte[] hb; // Non-null only for heap buffers
  10. final int offset;
  11. boolean isReadOnly; // Valid only for heap buffers
  12. /**
  13. * Allocates a new byte buffer.
  14. *
  15. * The new buffer's position will be zero, its limit will be its
  16. * capacity, its mark will be undefined, and each of its elements will be
  17. * initialized to zero.
  18. *
  19. * 该方法主要用来instance ByteBuffer,很重要的一个方法。
  20. *
  21. */
  22. public static ByteBuffer allocate(int capacity) {
  23. if (capacity < 0)
  24. throw new IllegalArgumentException();
  25. return new HeapByteBuffer(capacity, capacity);
  26. }
  27. /**
  28. * Relative get method. Reads the byte at this buffer's
  29. * current position, and then increments the position.
  30. *
  31. */
  32. public abstract byte get();
  33. /**
  34. * Relative put method;(optional operation).
  35. *
  36. * Writes the given byte into this buffer at the current
  37. * position, and then increments the position.
  38. */
  39. public abstract ByteBuffer put(byte b);
  40. /**
  41. * Relative bulk get method.
  42. */
  43. public ByteBuffer get(byte[] dst) {
  44. return get(dst, 0, dst.length);
  45. }
  46. /**
  47. * Relative bulk put method;(optional operation).
  48. *
  49. * This method transfers the entire content of the given source
  50. * byte array into this buffer. An invocation of this method of the
  51. * form dst.put(a) behaves in exactly the same way as the
  52. * invocation
  53. */
  54. public final ByteBuffer put(byte[] src) {
  55. return put(src, 0, src.length);
  56. }
  57. /**
  58. * Allocates a new direct byte buffer.
  59. */
  60. public static ByteBuffer allocateDirect(int capacity) {
  61. return new DirectByteBuffer(capacity);
  62. }
  63. /**
  64. * Wraps a byte array into a buffer.
  65. *
  66. * 该方法也是用来实例化ByteBuffer对象,和allocate(int capacity)目的一样。
  67. */
  68. public static ByteBuffer wrap(byte[] array) {
  69. return wrap(array, 0, array.length);
  70. }
  71. /**
  72. *Compacts this buffer
  73. */
  74. public abstract ByteBuffer compact();
  75. }

基于ByteBuffer深入理解读取和写入数据原理

  1. //1、初始化ByteBuffer
  2. ByteBuffer buffer=ByteBuffer.allocate(10);
  3. position=0
  4. limit=10 //初始化时limit等于buffer的容量
  5. capacity=10 //初始化容量
  6. //2、往buffer里写入数据
  7. buffer.put("python".getBytes());
  8. //每写入一个字节就会使position往后移动一位
  9. position=6
  10. limit=10
  11. capacity=10
  12. //3、当需要从buffer中读取数据时,需要调用flip()方法。
  13. //flip方法是将limit移动到position位置,将position位置移动到buffer开始位置即下标0。
  14. position=0
  15. limit=6
  16. capacity=10
  17. 分析从buffer中读取数据时为什么需要调用flip()方法
  18. 如果不调用flip()方法,那么position6limit10,由于调用buffer.get()方法是从position位置开始一直往下读数据,直到limit位置,那么读出来的数据就是0000(默认初始化时就是全部填充0)
  19. 只有调用了flip之后,position设置为0,limit设置为6,那么循环调用buffer.get()方法时,才能取出python数据。limit就是限制从buffer中取数的
  20. ByteBuffer buffer = ByteBuffer.allocate(10);
  21. // buffer对象中写入数据
  22. buffer.put("Python".getBytes());
  23. buffer.flip();
  24. // buffer对象读取数据
  25. while (buffer.hasRemaining()) {
  26. System.out.print((char) buffer.get());
  27. }
  28. 备注:flip方法非常重要,每次从Buffer对象中读取数据时都要调用该方法。
  29. //调用clear()方法
  30. clear方法使得
  31. position=0
  32. limit=10
  33. capacity=10
  34. This method does not actually erase the data in the buffer, but it is named as if it did because it will most often be used in situations in which that might as well be the case.
  35. 备注:clear方法并不像其名字一样清空Buffer中的数据。
  36. clear方法是用的场景并不多,大都数时候都是使用flip方法。

put方法

Buffer 的put 方法

  1. 写模式下,往buffer里写一个字节,并把postion移动一位。写模式下,一般limitcapacity相等

flip方法
Buffer 的flip 方法

  1. 写完数据,需要开始读的时候,将postion复位到0,并将limit设为当前postion

get方法
Buffer 的get方法

  1. buffer里读一个字节,并把postion移动一位。上限是limit,即写入数据的最后位置

clear方法
Buffer 的clear方法

  1. position置为0,并不清除buffer内容

总结

  1. Bufferjava nio中扮演很重要的一个角色,nio的操作都是基于Buffer来实现的。因此掌握并理解好Buffer非常的重要。

参考

1、http://tutorials.jenkov.com/java-nio/index.html
2、http://www.importnew.com/20061.html?utm_source=tuicool&utm_medium=referral
3、JDK源码

发表评论

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

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

相关阅读

    相关 NIOBuffer

    Buffer 其实在Buffer中官方的javadoc中已经讲得非常清楚了,本篇博客是本人做为笔记使用。 下面是我截取的javadoc很详细的介绍了关于mark,po

    相关 NIOBuffer

    在上一篇文章中聊了一下[Channel][],这篇文章聊一下Java NIO中的另一个重要的组件:`Buffer`。 Buffer的概念 首先我们先看一下`Buffer

    相关 NIOBuffer channel

    java NIO的通道类似流,但又有些不同: 既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的。 通道可以异步地读写。 通道中的数据总是要先读到一个Buffe

    相关 Java NIOBuffer

    缓冲区基础 本质上,缓冲区是就是一个数组。所有的缓冲区都具有四个属性来提供关于其所包含的数组的信息。它们是: 容量(Capacity) 缓冲区能够容纳的数据元素的

    相关 NIOBuffer

    > Java NIO中的Buffer用于和NIO通道进行交互。数据是从通道读入缓冲区,从缓冲区写入到通道中的。缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内

    相关 java NIObuffer

    Java NIO中的Buffer用于和NIO通道进行交互。如你所知,数据是从通道读入缓冲区,从缓冲区写入到通道中的。 缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内