📌 Java NIO Buffer

简介: Java NIO缓冲区在与NIO通道交互时使用。数据从通道读取到缓冲区,然后从缓冲区写入通道。缓冲区本质上是一块内存,可以在其中写入数据,然后再进行读取。这个内存块被封装在一个NIOBuffer对象中,该对象提供了一组方法,可以更容易地使用内存块。

Java NIO缓冲区在与NIO通道交互时使用。数据从通道读取到缓冲区,然后从缓冲区写入通道。

缓冲区本质上是一块内存,可以在其中写入数据,然后再进行读取。这个内存块被封装在一个NIOBuffer对象中,该对象提供了一组方法,可以更容易地使用内存块。

Buffer基础用法:

  1. 写入数据到Buffer缓冲区中
  2. 调用buffer.flip(),转换Buffer缓冲区读写模式
  3. Buffer缓冲区中读取数据
  4. 调用buffer.clear()buffer.compact()对缓冲区数据进行处理
// 使用缓存区进行内存分配:
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
// 从Channel中读取数据,写入到Buffer中:
int read = fileChannel.read(byteBuffer);
while (-1 != read) {
    // flip转换读写模式:
    byteBuffer.flip();
    while (byteBuffer.hasRemaining()) {
        System.out.print((char) byteBuffer.get());
    }
    // 清除缓冲区内容:
    byteBuffer.clear();
    read = fileChannel.read(byteBuffer);
}

将数据写入缓冲区时,缓冲区会跟踪写入的数据量。一旦需要读取数据,就需要使用flip()方法调用将缓冲区从写入模式切换到读取模式。在读取模式下,缓冲区允许您读取写入缓冲区的所有数据。

一旦读取了所有数据,就需要清除缓冲区,以便再次写入。可以通过两种方式来实现:通过调用clear()或通过调用compact()clear()方法清除整个缓冲区。compact()方法只清除您已经读取的数据。任何未读数据都会移动到缓冲区的开头,现在数据将在未读数据之后写入缓冲区。

Buffer核心属性:

缓冲区有三个您需要熟悉的属性:capacity缓冲区容量position指针索引位置limit缓冲区限制

position位置和limit限制的含义取决于缓冲区是处于读取模式还是写入模式。无论缓冲模式如何,capacity容量含义不变。

public abstract class Buffer {
  // ......
    // Invariants: mark <= position <= limit <= capacity
    private int mark = -1;  // 标记
    private int position = 0;
    private int limit;
    private int capacity;
}
  1. Capacity容量:

Buffer作为一个内存块,缓冲区有一定的固定大小,也称为“容量”。只能将容量字节、长度、字符等写入缓冲区。一旦缓冲区已满,就需要清空它(读取数据或清除它),然后才能向其中写入更多数据。

  1. Position指针位置:

指针位置,下一个要被读或写的元素索引,每次读写缓冲区数据时都会改变值,为下次读写做准备。

将数据写入缓冲区时,会在某个位置进行写入。最初位置为0。当一个字节、长等已写入缓冲区时,该位置将前进到指向缓冲区中的下一个单元格以插入数据。位置可以最大化为容量-1

当从缓冲区读取数据时,也可以从给定的位置读取数据。将“缓冲区”从写入模式翻转到读取模式时,位置会重置回0。当从缓冲区读取数据时,从位置读取数据,位置将前进到下一个要读取的位置。

  1. limit缓冲区限制:

表示缓冲区的当前终点,不能对缓冲区超过极限的位置进行读写操作。且极限是可以修改的。

在写入模式下,缓冲区的限制是可以写入缓冲区的数据量的限制。在写入模式下,限制等于缓冲区的容量。

将“缓冲区”切换到读取模式时,limit表示可以从数据中读取多少数据的限制。所以,当将缓冲区翻转到读取模式时,将限制设置为写入模式的写入位置。换句话说,可以读取写入的字节数(限制设置为写入的字节数量,由位置标记)。

Buffer常用类型:

Java NIO具有以下缓冲区类型:

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

Buffer分配内存(创建Buffer实例):

要获得Buffer对象,您必须首先对其进行分配。每个Buffer类都有一个allocate()方法来完成此操作。

ByteBuffer分配1024字节内存:

// 给Buffer分配内存:
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

CharBuffer分配1024字符:

CharBuffer charBuffer = CharBuffer.allocate(1024);

Buffer中写入数据:

可以通过两种方式向缓冲区中写入数据:

  • 可以从Channel通道中获取到数据,写入Buffer缓冲区。
// 读取Channel中的数据到Buffer中:
int bytesRead = inChannel.read(buf);
  • 可以通过调用put()方法,直接写入数据到Buffer缓冲区中。
buf.put(127);

flip()方法 转换Buffer读写模式:

flip()方法可以转换Buffer的读写模式,将Buffer从写入模式切换到读取模式,调用flip()可以将position设置为0,并将limit设置为些时的position位置。

换句话说,position现在标记读取位置,limit标记有多少字节、字符等被写入缓冲区(可以读取的字节、字符等等的限制)。

Buffer中读取数据:

可以通过两种方式从缓冲区中读取数据:

  • 可以读取Buffer中的数据到Channel中。
// 向通道中写入数据:
int bytesWritten = inChannel.write(buf);
  • 可以通过get()方法获取到Buffer中的数据。
byte aByte = buf.get();

Buffer还提供了额外方法用于操作positionlimit等属性的方法:

  • reword()

Buffer.rewind()position位置设置回0,这样您就可以重新读取缓冲区中的所有数据。限制保持不变,因此仍然标记可以从缓冲区读取多少元素(字节、字符等)。

  • mark()reset()

mark() 是在读取时,做一个标记,即使 position 改变,只要调用 reset() 就能回到 mark 的位置。注意:rewind()flip() 都会清除 mark 位置。

buffer.mark();
//call buffer.get() a couple of times, e.g. during parsing.
buffer.reset();  //set position back to mark.
  • clear()compact()

一旦完成了从缓冲区中读取数据,就必须使缓冲区做好再次写入的准备。您可以通过调用clear()compact()来实现这一点。

如果调用clear(),则位置将设置回0,并限制容量。换句话说,缓冲区被清除。缓冲区中的数据不会被清除。只有指示可以将数据写入缓冲区的位置的标记。

当您调用clear()时,如果缓冲区中有任何未读数据,则该数据将被“遗忘”,这意味着您不再有任何标记来指示哪些数据已被读取,哪些数据未被读取。

如果缓冲区中仍有未读数据,并且您想稍后读取,但需要先进行一些写入,请调用compact()而不是clear()

compact()将所有未读数据复制到Buffer的开头。然后它将位置设置在最后一个未读元素的正后方。limit属性仍然设置为capacity,就像clear()一样。现在缓冲区已准备好写入,但不会覆盖未读数据。

  • equals()compareTo()

equals()两个缓冲区相等,如果:它们属于相同的类型(字节、字符、int等)它们在缓冲区中具有相同数量的剩余字节、字符等。所有剩余的字节、字符等都是相等的。正如您所看到的,equals只比较Buffer的一部分,而不是其中的每一个元素。事实上,它只是比较Buffer中的其余元素。

compareTo()方法比较两个缓冲区的剩余元素(字节、字符等),用于例如排序例程。如果出现以下情况,则认为缓冲区比另一个缓冲区“小”:与另一个缓冲器中的对应元素相等的第一个元素小于另一个缓冲区中的元素。所有元素都是相等的,但第一个缓冲区在第二个缓冲区之前用完了元素(它的元素更少)。

相关文章
|
23天前
|
存储 监控 Java
深入探索Java语言的NIO(New I/O)技术
深入探索Java语言的NIO(New I/O)技术
|
9天前
|
Java 视频直播 数据库连接
Java I/O 模型详解:BIO、NIO 与 AIO 的特性与应用
Java I/O 模型详解:BIO、NIO 与 AIO 的特性与应用
15 2
|
9天前
|
存储 网络协议 Java
Java I/O 详解:基础、文件操作与 NIO 实践
Java I/O 详解:基础、文件操作与 NIO 实践
14 1
|
11天前
|
网络协议 Java API
全网最清晰JAVA NIO,看一遍就会
全网最清晰JAVA NIO,看一遍就会
27 0
|
1月前
|
监控 Java
Java一分钟之-NIO:非阻塞IO操作
【5月更文挑战第14天】Java的NIO(New IO)解决了传统BIO在高并发下的低效问题,通过非阻塞方式提高性能。NIO涉及复杂的选择器和缓冲区管理,易出现线程、内存和中断处理的误区。要避免这些问题,可以使用如Netty的NIO库,谨慎设计并发策略,并建立标准异常处理。示例展示了简单NIO服务器,接收连接并发送欢迎消息。理解NIO工作原理和最佳实践,有助于构建高效网络应用。
22 2
|
1月前
|
消息中间件 存储 Java
【Java NIO】那NIO为什么速度快?
是这样的,在NIO零拷贝出现之前,一个I/O操作会将同一份数据进行多次拷贝。可以看下图,一次I/O操作对数据进行了四次复制,同时来伴随两次内核态和用户态的上下文切换,众所周知上下文切换是很耗费性能的操作。
38 1
【Java NIO】那NIO为什么速度快?
|
24天前
|
存储 监控 Java
Java nio非阻塞io
Java nio非阻塞io
|
1月前
|
缓存 Java API
Java NIO和IO之间的区别
NIO(New IO),这个库是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多。在Java API中提供了两套NIO,一套是针对标准输入输出NIO,另一套就是网络编程NIO。
23 1
|
1月前
|
监控 Java 开发者
深入理解 Java 网络编程和 NIO
【4月更文挑战第19天】Java网络编程基于Socket,但NIO(非阻塞I/O)提升了效率和性能。NIO特点是非阻塞模式、选择器机制和缓冲区,适合高并发场景。使用NIO涉及通道、选择器和事件处理,优点是高并发、资源利用率和可扩展性,但复杂度、错误处理和性能调优是挑战。开发者应根据需求选择是否使用NIO,并深入理解其原理。
|
1月前
|
存储 监控 Java
浅谈Java NIO
浅谈Java NIO
12 0