Java I/O缓冲区

Java IO教程 - Java I/O缓冲区

什么是NIO?

在NIO中,我们处理I/O操作的通道和缓冲区。

像流一样的通道表示数据源/接收器和用于数据传输的Java程序之间的连接。

通道提供双向数据传输设施。我们可以使用通道来读取数据以及写入数据。根据我们的需要,我们可以获得只读通道,只写通道或读写通道。

在基于流的I/O中,数据传输的基本单位是一个字节。在基于通道的NIO中,数据传输的基本单位是缓冲器。

缓冲区具有确定其可以包含的数据的上限的固定容量。

在基于通道的I/O中,我们将数据写入缓冲区,并将该缓冲区传递到写入数据的通道。

为了从数据源读取数据,我们向一个通道传递一个缓冲区。通道将数据从数据源读入缓冲区。


缓冲区

缓冲区是固定长度的数据容器。有一个单独的缓冲区类型来保存每种类型的基本值的数据,除了布尔类型值。

缓冲区是我们程序中的一个对象。我们有一个单独的类来表示每种类型的缓冲区。

所有缓冲区类都继承自一个抽象的Buffer类。包含原始值的缓冲区类如下:

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

不同的缓冲区保存不同数据类型的数据。例如,ByteBuffer保存字节值; ShortBuffer保存短值;一个CharBuffer保存字符,等等。


缓冲区属性

以下是缓冲区的四个重要属性。

  • Capacity
  • Position
  • Limit
  • Mark

缓冲区的容量是它可以容纳的元素的最大数量。并且当创建缓冲器时它是固定的。

我们可以通过调用hasArray()方法检查缓冲区是否由数组支持,如果缓冲区由数组支持则返回true。

我们可以通过使用缓冲对象的array()方法来访问支持数组。

一旦我们访问了后台数组,对该数组所做的任何更改都将反映在缓冲区中。

缓冲区具有返回其容量的capacity()方法。

缓冲区创建

我们可以使用特定缓冲区类的allocate()工厂方法创建一个缓冲区,如下所示:

以下代码创建一个容量为8的字节缓冲区

ByteBuffer bb  = ByteBuffer.allocate(8);

获得容量

int capacity = bb.capacity();

以下代码创建一个容量为1024的字符缓冲区

CharBuffer cb  = CharBuffer.allocate(1024);

字节缓冲区有一个名为allocateDirect()的方法,它创建一个字节缓冲区,从操作系统内存中分配内存,而不是从JVM堆中分配内存。

我们可以使用ByteBuffer类的isDirect()方法来检查缓冲区是直接还是非直接。

// Create a  direct byte   buffer of  512  bytes capacity
ByteBuffer bbd = ByteBuffer.allocateDirect(512);

另一种创建缓冲区的方法是使用缓冲区的static wrap()方法包装数组。

byte[]  byteArray = new byte[512];
ByteBuffer bb  = ByteBuffer.wrap(byteArray);

我们可以使用相同的技术来创建缓冲区来存储其他原始值。

当我们创建一个缓冲区时,缓冲区的所有元素都被初始化为零值。

缓冲区索引位置

缓冲区的每个元素都有一个索引。第一个元素的索引为0,最后一个元素的索引为capacity-1。

创建缓冲区时,其位置设置为0,其限制等于其容量。

我们可以使用它的重载position()方法获取/设置缓冲区的位置。

position()方法返回缓冲区位置的当前值。

position(int newPosition)方法将缓冲区的位置设置为指定的newPosition值,并返回缓冲区的引用。

我们可以使用它的重载limit()方法获取/设置缓冲区的限制。

limit()方法返回缓冲区限制的当前值。limit(int newLimit)方法将缓冲区的限制设置为指定的newLimit值,并返回缓冲区的引用。

我们可以使用mark()方法为缓冲区的位置添加书签。当我们调用mark()方法时,缓冲区将其位置的当前值存储为其标记值。我们可以通过使用reset()方法将缓冲区的位置设置为之前加书签的值。

缓冲区的标记在创建时未定义。只有当定义了它的标记时,我们才必须在缓冲区上调用reset()方法。否则,reset()方法会抛出InvalidMarkException异常。

以下代码创建一个新缓冲区并显示其四个属性。

import java.nio.ByteBuffer;
import java.nio.InvalidMarkException;

public class Main {
  public static void main(String[] args) {
    ByteBuffer bb = ByteBuffer.allocate(8);

    System.out.println("Capacity: " + bb.capacity());
    System.out.println("Limit: " + bb.limit());
    System.out.println("Position: " + bb.position());

    // The mark is not set for a new buffer. Calling the
    // reset() method throws a runtime exception if the mark is not set.
    try {
      bb.reset();
      System.out.println("Mark: " + bb.position());
    } catch (InvalidMarkException e) {
      System.out.println("Mark is not  set");
    }
  }
}

上面的代码生成以下结果。