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

相关文章
|
2月前
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用
|
13天前
|
Java
"揭秘Java IO三大模式:BIO、NIO、AIO背后的秘密!为何AIO成为高并发时代的宠儿,你的选择对了吗?"
【8月更文挑战第19天】在Java的IO编程中,BIO、NIO与AIO代表了三种不同的IO处理机制。BIO采用同步阻塞模型,每个连接需单独线程处理,适用于连接少且稳定的场景。NIO引入了非阻塞性质,利用Channel、Buffer与Selector实现多路复用,提升了效率与吞吐量。AIO则是真正的异步IO,在JDK 7中引入,通过回调或Future机制在IO操作完成后通知应用,适合高并发场景。选择合适的模型对构建高效网络应用至关重要。
22 2
|
7天前
|
存储 网络协议 Java
【Netty 神奇之旅】Java NIO 基础全解析:从零开始玩转高效网络编程!
【8月更文挑战第24天】本文介绍了Java NIO,一种非阻塞I/O模型,极大提升了Java应用程序在网络通信中的性能。核心组件包括Buffer、Channel、Selector和SocketChannel。通过示例代码展示了如何使用Java NIO进行服务器与客户端通信。此外,还介绍了基于Java NIO的高性能网络框架Netty,以及如何用Netty构建TCP服务器和客户端。熟悉这些技术和概念对于开发高并发网络应用至关重要。
25 0
|
2月前
|
安全 Java Linux
(七)Java网络编程-IO模型篇之从BIO、NIO、AIO到内核select、epoll剖析!
IO(Input/Output)方面的基本知识,相信大家都不陌生,毕竟这也是在学习编程基础时就已经接触过的内容,但最初的IO教学大多数是停留在最基本的BIO,而并未对于NIO、AIO、多路复用等的高级内容进行详细讲述,但这些却是大部分高性能技术的底层核心,因此本文则准备围绕着IO知识进行展开。
111 1
|
2月前
|
安全 Java
【Java】已解决java.nio.channels.OverlappingFileLockException异常
【Java】已解决java.nio.channels.OverlappingFileLockException异常
49 1
|
2月前
|
Java
【Java】已解决java.nio.channels.ClosedChannelException异常
【Java】已解决java.nio.channels.ClosedChannelException异常
131 1
|
2月前
|
Java
【Java】已解决java.nio.channels.FileLockInterruptionException异常
【Java】已解决java.nio.channels.FileLockInterruptionException异常
23 1
|
2月前
|
Java
Java中的NIO编程详解
Java中的NIO编程详解
|
2月前
|
Java 大数据
如何在Java中进行网络编程:Socket与NIO
如何在Java中进行网络编程:Socket与NIO
|
2月前
|
Java
Java中的NIO编程详解
Java中的NIO编程详解
下一篇
云函数