image.png

1.向 Buffer 中写数据

  1. public static void writeBuffer() {
  2. ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
  3. // byte 范围是多少? byte 由8bit表示,2^8=256,范围[-128~127]
  4. byte b = 127;
  5. // 填充一个 byte 值
  6. byteBuffer.put(b);
  7. // 在指定位置填充一个 byte 值
  8. byteBuffer.put(20, b);
  9. // 将一个数组中的值填充进去
  10. byte[] byteArray = "something".getBytes();
  11. byteBuffer.put(byteArray);
  12. // 在指定位置填充一个 byte 数组
  13. //参数一:byte数组 参数二:src开始位置 参数三:有效数据长度
  14. byteBuffer.put(byteArray, 0, byteArray.length);
  15. //上述这些方法需要自己控制 Buffer 大小,不能超过 capacity,超过会抛 java.nio.BufferOverflowException 异常。
  16. // 对于 Buffer 来说,另一个常见的操作中就是,我们要将来自 Channel 的数据填充到 Buffer 中,
  17. // 在系统层面上,这个操作我们称为读操作,因为数据是从外部(文件或网络等)读到内存中。
  18. // ps:伪代码,这段代码无法正常运行..
  19. try {
  20. SocketChannel socketChannel = socketChannel();
  21. //read方法会返回读取的数据量num,相对于buffer来说,channel读取 对应 buffer 写操作。
  22. int num = socketChannel.read(byteBuffer);
  23. } catch (IOException e) {
  24. }
  25. }

2.flip()方法

flip方法将 Buffer 从写模式切换到读模式。
调用flip()方法会将 position 设回0,并将 limit 设置成之前 position 的值
换句话说,position 现在用于标记读的位置,limit 表示之前写进了多少个 byte、char 等, 现在就能读取多少个 byte、char 等。

3.从 Buffer 中读取数据

  1. public static void readBuffer(ByteBuffer byteBuffer) {
  2. // 1. 按照position顺序读取,每get一次,position + 1
  3. byte val1 = byteBuffer.get();
  4. // 2. 获取指定位置的数据
  5. byte val2 = byteBuffer.get(10);
  6. // 3. 将buffer中的数据,拷贝到一个指定的数组中
  7. byte[] bytes = new byte[1024];
  8. byteBuffer.get(bytes);
  9. // 4. 另一个经常使用的方法,直接返回Buffer内部的byte[]数组
  10. String str = new String(byteBuffer.array());
  11. // 5.
  12. // 网络编程中,我们将数据发送至对端 或者 使用FileChannel将内存中的数据写入到硬盘
  13. // 这种操作,我们通常称之为 Channel 的写操作,与之对应的 Buffer 就是 读操作。
  14. // ps:伪代码,这段代码无法正常运行..
  15. try {
  16. SocketChannel socketChannel = socketChannel();
  17. // byteBuffer.flip(); 一定要注意!
  18. socketChannel.write(byteBuffer);
  19. } catch (IOException e) {
  20. }
  21. }

使用 Buffer 读写数据步骤

  1. 写入数据到 Buffer
  2. 调用 flip()方法
  3. 从 Buffer 中读取数据
  4. 调用 clear()方法或者 compact()方法,准备下一次的写入

当向 buffer 写入数据时,buffer 会记录下写了多少数据。一旦要读取数据,需要通过 flip()方法将 Buffer 从写模式切换到读模式。在读模式下,可以读取之前写入到 buffer 的所有数据。
一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。
有两种方式能清空缓冲区:调用 clear()或 compact()方法。

  • clear()方法会清空整个缓冲区。(没有真的清除数据,只是重置了指针)

image.png

  • compact()方法只会清除已经读过的数据。(会删除已读的数据,把剩余的未读数据挪到开始的地方)

image.png

  1. public class BufferMethod {
  2. public static void main(String[] args) {
  3. System.out.println("------Test get and put-------------");
  4. ByteBuffer buffer = ByteBuffer.allocate(32);
  5. buffer.put((byte) 'a')//0
  6. .put((byte) 'b')//1
  7. .put((byte) 'c')//2
  8. .put((byte) 'd')//3
  9. .put((byte) 'e')//4
  10. .put((byte) 'f');//5
  11. System.out.println("before flip()" + buffer);
  12. /* 转换为读取模式*/
  13. buffer.flip();
  14. System.out.println("before get():" + buffer);
  15. System.out.println((char)buffer.get());
  16. System.out.println("after get():" + buffer);
  17. /* position移动两位*/
  18. byte[] dst = new byte[10];
  19. buffer.get(dst, 0, 2);
  20. System.out.println("after get(dst, 0, 2):" + buffer);
  21. System.out.println("dst:" + new String(dst));
  22. /*绝对读写*/
  23. System.out.println("--------Test 绝对读写-------");
  24. ByteBuffer bb = ByteBuffer.allocate(32);
  25. System.out.println("before put(byte):" + bb);
  26. System.out.println("after put(byte):" + bb.put((byte) 'z'));
  27. /* put(2,(byte) 'c')不改变position的位置*/
  28. bb.put(2, (byte) 'c');
  29. System.out.println("after put(2,(byte) 'c'):" + bb);
  30. System.out.println(new String(bb.array()));
  31. /* get(index)不影响position的值*/
  32. System.out.println((char) buffer.get(2));
  33. System.out.println("after get(index):" + buffer);
  34. System.out.println("--------Test Clear And Compact--------");
  35. ByteBuffer buffer2 = ByteBuffer.allocate(32);
  36. buffer2.put((byte) 'x');
  37. System.out.println("before clear:" + buffer2);
  38. buffer2.clear();
  39. System.out.println("after clear:" + buffer2);
  40. System.out.println(new String(buffer2.array()));
  41. /*放入4个字节,position移动到下个可写入的位置,也就是4*/
  42. buffer2.put("abcd".getBytes());
  43. System.out.println("before compact:" + buffer2);
  44. buffer2.flip();//将position设回0,并将limit设置成之前position的值*/
  45. System.out.println("after flip:" + buffer2);
  46. /*compact()方法将所有未读的数据拷贝到Buffer起始处。*/
  47. /* 然后将position设到最后一个未读元素正后面。*/
  48. System.out.println("还有数据未读,个数:" + buffer2.remaining());
  49. buffer2.compact();
  50. System.out.println("after compact:" + buffer2);
  51. System.out.println(new String(buffer2.array()));
  52. System.out.println("--------Test rewind--------");
  53. buffer.clear();
  54. buffer.position(10);/*移动position到10*/
  55. buffer.limit(15);/*限定最大可写入的位置为15*/
  56. System.out.println("before rewind:" + buffer);
  57. buffer.rewind();/*将position设回0*/
  58. System.out.println("before rewind:" + buffer);
  59. System.out.println("--------Test mark AND reset----------");
  60. buffer = ByteBuffer.allocate(20);
  61. System.out.println("buffer = " + buffer);
  62. buffer.clear();
  63. buffer.position(5);/*移动position到5*/
  64. buffer.mark();/*记录当前position的位置*/
  65. buffer.position(10);/*移动position到10*/
  66. System.out.println("before reset:" + buffer);
  67. buffer.reset();/*复位position到记录的地址*/
  68. System.out.println("after reset:" + buffer);
  69. }
  70. }