NIO之Buffer解读(上)

简介: NIO之Buffer解读

Buffer 简介

Java NIO 中的 Buffer 用于和 NIO 通道进行交互。数据是从通道读入缓冲区,从缓冲 区写入到通道中的。

缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装 成 NIO Buffer 对象,并提供了一组方法,用来方便的访问该块内存。缓冲区实际上是 一个容器对象,更直接的说,其实就是一个数组,在 NIO 库中,所有数据都是用缓冲 区处理的。在读取数据时,它是直接读到缓冲区中的; 在写入数据时,它也是写入到 缓冲区中的;任何时候访问 NIO 中的数据,都是将它放到缓冲区中。而在面向流 I/O 系统中,所有数据都是直接写入或者直接将数据读取到 Stream 对象中。

在 NIO 中,所有的缓冲区类型都继承于抽象类 Buffer,最常用的就是 ByteBuffer, 对于 Java 中的基本类型,基本都有一个具体 Buffer 类型与之相对应,它们之间的继 承关系如下图所示:

Buffer 的基本用法

使用步骤

1、使用 Buffer 读写数据,一般遵循以下四个步骤:

(1)写入数据到 Buffer

(2)调用 flip()方法

(3)从 Buffer 中读取数据

(4)调用 clear()方法或者 compact()方法

当向 buffer 写入数据时,buffer 会记录下写了多少数据。一旦要读取数据,需要通过 flip()方法将 Buffer 从写模式切换到读模式。在读模式下,可以读取之前写入到 buffer 的所有数据。一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。有 两种方式能清空缓冲区:调用 clear()或 compact()方法。clear()方法会清空整个缓冲 区。compact()方法只会清除已经读过的数据。任何未读的数据都被移到缓冲区的起 始处,新写入的数据将放到缓冲区未读数据的后面。

使用 Buffer 的例子

1. @Test
2. public void testConect2() throws IOException {
3. RandomAccessFile aFile = new RandomAccessFile("d:\\atguigu/01.txt", "rw");
4. FileChannel inChannel = aFile.getChannel();
5. 
6. //create buffer with capacity of 48 bytes
7. ByteBuffer buf = ByteBuffer.allocate(48);
8. int bytesRead = inChannel.read(buf); //read into buffer. 
9. while (bytesRead != -1) {
10.             buf.flip(); //make buffer ready for read
11. while(buf.hasRemaining()){
12.                 System.out.print((char) buf.get()); // read 1 byte at a time
13.             }buf.clear(); //make buffer ready for writing
14.             bytesRead = inChannel.read(buf);
15.         }
16.         aFile.close();
17.     }

使用 IntBuffer 的例子

1. @Test
2. public void testConect3() throws IOException {
3. // 分配新的 int 缓冲区,参数为缓冲区容量
4. // 新缓冲区的当前位置将为零,其界限(限制位置)将为其容量。
5. // 它将具有一个底层实现数组,其数组偏移量将为零。
6. IntBuffer buffer = IntBuffer.allocate(8);
7. for (int i = 0; i < buffer.capacity(); ++i) {
8. int j = 2 * (i + 1);
9. // 将给定整数写入此缓冲区的当前位置,当前位置递增
10.             buffer.put(j);
11.         }
12. // 重设此缓冲区,将限制设置为当前位置,然后将当前位置设置为 0
13.         buffer.flip();
14. // 查看在当前位置和限制位置之间是否有元素
15. while (buffer.hasRemaining()) {
16. // 读取此缓冲区当前位置的整数,然后当前位置递增
17. int j = buffer.get();
18.             System.out.print(j + " ");
19.         }
20.     }

Buffer 的 capacity、position 和 limit

为了理解 Buffer 的工作原理,需要熟悉它的三个属性:

- Capacity

- Position

- limit

position 和 limit 的含义取决于 Buffer 处在读模式还是写模式。不管 Buffer 处在什么 模式,capacity 的含义总是一样的。

这里有一个关于 capacity,position 和 limit 在读写模式中的说明:

capacity

作为一个内存块,Buffer 有一个固定的大小值,也叫“capacity”.你只能往里写 capacity 个 byte、long,char 等类型。一旦 Buffer 满了,需要将其清空(通过读数 据或者清除数据)才能继续写数据往里写数据。

position

1)写数据到 Buffer 中时,position 表示写入数据的当前位置,position 的初始值为 0。当一个 byte、long 等数据写到 Buffer 后, position 会向下移动到下一个可插入 数据的 Buffer 单元。position 最大可为 capacity – 1(因为 position 的初始值为 0).

2)读数据到 Buffer 中时,position 表示读入数据的当前位置,如 position=2 时表 示已开始读入了 3 个 byte,或从第 3 个 byte 开始读取。通过 ByteBuffer.flip()切换到 读模式时 position 会被重置为 0,当 Buffer 从 position 读入数据后,position 会下 移到下一个可读入的数据 Buffer 单元。

limit

1)写数据时,limit 表示可对 Buffer 最多写入多少个数据。写模式下,limit 等于 Buffer 的 capacity。

2)读数据时,limit 表示 Buffer 里有多少可读数据(not null 的数据),因此能读到 之前写入的所有数据(limit 被设置成已写数据的数量,这个值在写模式下就是 position)。

Buffer 的类型

- ByteBuffer

- MappedByteBuffer

- CharBuffer

- DoubleBuffer

- FloatBuffer

- IntBuffer

- LongBuffer

- ShortBuffer

这些 Buffer 类型代表了不同的数据类型。换句话说,就是可以通过 char,short,int, long,float 或 double 类型来操作缓冲区中的字节。

Buffer 分配和读写数据

Buffer 分配

要想获得一个 Buffer 对象首先要进行分配。 每一个 Buffer 类都有一个 allocate 方法。 下面是一个分配 48 字节 capacity 的 ByteBuffer 的例子。

ByteBuffer buf = ByteBuffer.allocate(48);

这是分配一个可存储 1024 个字符的 CharBuffer:

CharBuffer buf = CharBuffer.allocate(1024);


相关文章
|
5月前
|
存储 编解码 移动开发
技术笔记:NIO流—理解Buffer、Channel概念和NIO的读写操作
技术笔记:NIO流—理解Buffer、Channel概念和NIO的读写操作
39 1
|
1月前
|
Java
让星星⭐月亮告诉你,Java NIO之Buffer详解 属性capacity/position/limit/mark 方法put(X)/get()/flip()/compact()/clear()
这段代码演示了Java NIO中`ByteBuffer`的基本操作,包括分配、写入、翻转、读取、压缩和清空缓冲区。通过示例展示了`position`、`limit`和`mark`属性的变化过程,帮助理解缓冲区的工作原理。
29 2
|
6月前
|
Java 索引
📌 Java NIO Buffer
Java NIO缓冲区在与NIO通道交互时使用。数据从通道读取到缓冲区,然后从缓冲区写入通道。 缓冲区本质上是一块内存,可以在其中写入数据,然后再进行读取。这个内存块被封装在一个NIOBuffer对象中,该对象提供了一组方法,可以更容易地使用内存块。
|
存储 网络协议 Java
Netty入门到超神系列-Java NIO 三大核心(selector,channel,buffer)
选择器,也叫多路复用器,Java的NIO通过selector实现一个线程处理多个客户端链接,多个channel可以注册到同一个Selector,Selector能够监测到channel上是否有读/写事件发生,从而获取事件和对事件进行处理,所以Selector切到哪个channel是由事件决定的。当线程从某个客户端通道未读取到数据时,可以把空闲时间用来做其他任务,性能得到了提升。
154 0
|
弹性计算 Java API
Netty入门到超神系列-Java NIO 三大核心(selector,channel,buffer)
理解Selector 和 Channel Selector 选择器,也叫多路复用器,可以同时处理多个客户端连接,多路复用器采用轮询机制来选择有读写事件的客户端链接进行处理。 通过 Selector ,一个 I/O 线程可以并发处理 N 个客户端连接和读写操作,这解决了传统同步阻塞 I/O 一连接一线程模型,架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。 由于它的读写操作都是非阻塞的,这就可以充分提升 IO 线程的运行效率,避免由于频繁 I/O 阻塞导致的线程挂起。
252 0
|
存储 Java
NIO之Buffer解读(下)
NIO之Buffer解读(下)
java Nio(二): Buffer(缓冲区)的数据存取
java Nio(二): Buffer(缓冲区)的数据存取
java Nio(二): Buffer(缓冲区)的数据存取
|
Java
Java NIO 中的 Buffer 缓冲区详解(下)
Java NIO 中的 Buffer 缓冲区详解
191 0
Java NIO 中的 Buffer 缓冲区详解(下)
|
设计模式 缓存 Java
NIO中Buffer的重要属性关系解析
NIO中Buffer的重要属性关系解析
189 0
|
存储 Java
小师妹学JavaIO之:NIO中那些奇怪的Buffer
小师妹学JavaIO之:NIO中那些奇怪的Buffer
小师妹学JavaIO之:NIO中那些奇怪的Buffer