Java NIO Buffer

Java NIO Buffer是用来与Channel交互的。如你所知,数据从Channel读取到Buffer,或者从Buffer写入Channel。

缓冲区本质上是一个内存块,您可以在其中读和写数据。NIO的Buffer对象是对该内存块的一个封装,其向外提供了一组方法,可以更轻松地使用该内存块。

Buffer 基础使用方式

使用Buffer读取和写入数据通常遵循以下四个步骤:

  • 写数据到Buffer
  • 调用 buffer.flip()
  • 从Buffer中读数据出来
  • 调用buffer.clear()或者buffer.compact()

当您将数据写入Buffer时,Buffer会跟踪记录写入了多少数据。一旦需要读取这些数据,就需要使用flip()方法,将Buffer从写模式切换到读模式。只有在在读模式下,你才可以读取Buffer中的所有之前写入的数据。

读取所有数据后,需要清除缓冲区,以使其可以再次写入。可以通过两种方式执行清理操作:调用clear()或调用compact()。 clear()方法清除整个缓冲区。 compact()方法仅清除您已经读取的数据。所有未读的数据都将移至缓冲区的开头,并且再次写入的时候,将在未读的数据之后写入,不会覆盖掉之前未读的数据。

这是一个简单的Buffer使用示例:

RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();

//create buffer with capacity of 48 bytes
ByteBuffer buf = ByteBuffer.allocate(48);

int bytesRead = inChannel.read(buf); //read into buffer.
while (bytesRead != -1) {

  buf.flip();  //make buffer ready for read

  while(buf.hasRemaining()){
      System.out.print((char) buf.get()); // read 1 byte at a time
  }

  buf.clear(); //make buffer ready for writing
  bytesRead = inChannel.read(buf);
}
aFile.close();

Buffer 的Capacity, Position and Limit

缓冲区本质上是一个内存块,您可以在其中读和写数据。NIO的Buffer对象是对该内存块的一个封装,其向外提供了一组方法,可以更轻松地使用该内存块。

我们需要了解缓冲区的三个属性,来更好的了解缓冲区的工作原理。这些是:

  • capacity
  • position
  • limit

position和limit的含义取决于缓冲区是处于读还是写模式。但是不管缓冲模式如何,capacity始终表示Buffer的最大容量,他的值是不会变的。

首先提供两张分别在读写模式下,Buffer三个属性的视图,在后面的各小结中将会用到。
Buffer 三个重要属性

Capacity

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

Position

向Buffer写入数据时(Buffer处于写模式),需要一个值来标记在内存块的哪一个位置开始写入,这个值就通过Position表示。Position最初值为0。将一些数据写入Buffer后,该位置将前进以指向Buffer中的下一个数据单元。位置最大可以变成容量-1。

从Buffer读取数据时(Buffer处于读模式),也需要从给定位置读取数据。这个值也同样的通过Position来表示。读写模式的切换下面会提到。

Limit

在写模式下,Limit表示可以写入Buffer的数据量。在写模式下,限制等于缓冲区的容量,即Capacity。

将缓冲区切换到读取模式时,Limit意味着可以从Buffer中读取多少数据。因此,当将缓冲区切换到读模式时,会将Limit值设置为写入模式的Position位置。换句话说,可以读取与写入的字节一样多的字节(限制设置为写入的字节数,该字节数由Position标记)。

Buffer Types

Java NIO提供以下缓冲区类型:

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

如您所见,这些缓冲区类型代表不同的数据类型。换句话说,不仅仅可以用字节(byte)向Buffer读写,也可以使用其他提供出来的类型。

MappedByteBuffer有点特殊,将在单独的章节介绍。

创建Buffer对象

要获取Buffer对象,您必须首先为它分配内存块。每个类型的Buffer类都有一个执行此操作的allocate()静态方法。下面是一个创建ByteBuffer的示例,容量为48个字节:

ByteBuffer buf = ByteBuffer.allocate(48);

这是一个为1024个字符分配一个CharBuffer的示例:

CharBuffer buf = CharBuffer.allocate(1024);

向Buffer中写入数据

有两种向Buffer中写入数据的方式

  1. 通过Channel向Buffer写入数据
  2. 通过Buffer自带的put()方法写入数据

通过Channel写入数据示例:

int bytesRead = inChannel.read(buf); //read into buffer.

通过put()方法写入数据

buf.put(127);

put()方法还有许多其他版本,提供多种方式将数据写入Buffer。例如,在特定位置写入或将字节数组写入。有关更多详细信息,请参见JavaDoc以获取具体的缓冲区实现。

flip()

flip()方法将Buffer从写模式切换到读模式。调用flip()会将Limit和Position的值相互交互。

也就是说,Limit将作为数据读取结束位置的标记,Position会作为数据读取的开始标记。需要注意的是flip()只能从写模式切入读模式。

从Buffer中读取数据

有两种方法从Buffer中读取数据:

  1. 通过Channel从Buffer中读取数据
  2. 通过Buffer自带的get()方法读取数据

通道读取数据的示例:

//read from buffer into channel.
int bytesWritten = inChannel.write(buf);

通过自带get()读取数据示例:

byte aByte = buf.get();

get()方法还有许多其他版本,允许您以多种不同方式从Buffer读取数据。例如,在特定位置读取或从Buffer读取字节数组。有关更多详细信息,请参见JavaDoc以获取具体的缓冲区实现。

rewind()

Buffer.rewind()可以将Position重置,使你可以重新读取Buffer中的所有数据。调用rewind()方法时Limit值保持不变。

clear() 和 compact()

当你完成读取操作想要重新开始写入的时候,必须使Buffer重新进入写模式。您可以通过调用clear()或调用compact()来实现。

如果调用clear(),则位Position将重新设置为0,Limit值也将重新设置。也可以理解为,缓冲区被清除。

如果在调用clear()时缓冲区中有任何未读取的数据,将再也读取不到。也即是说缓冲区被清零了。

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

compact()会将Position重新设置到未读数据的结尾,并将Limit放在正确的位置。现在,缓冲区已准备好进行写入,但是您不会覆盖未读取的数据。

mark() 和 reset()

您可以通过调用Buffer.mark()方法在Buffer中标记当前Position和Limit信息。稍后可以通过调用reset()方法将位置重置回到标记的位置。使用示例:

buffer.mark(); // mark 也会切入读模式

//调用 buffer.get() 获取数据

buffer.reset();  //set position back to mark.    

equals() 和 compareTo()

如果满足以下条件,则两个缓冲区相等:

  1. 相同类型的Buffer(字节,字符,整数等)
  2. 两个Buffer中已使用的数据单元数量相等
  3. 两个Buffer中各对应数据单元中数据相同
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值