3 Java NIO Buffer-翻译

本文深入讲解Java NIO的基础概念,包括Buffer的使用方法及其内部机制,如Capacity、Position和Limit等关键属性。同时介绍了不同类型的Buffer及如何进行数据读写。

Buffer是用来跟Channel进行交互的。正如你所知道的,数据都是从Channel读到Buffer中的,并从Buffer写入到Channel中的。

Buffer本质上是一块内存空间,你可以将数据写入到这里,并在之后读取它。这个内存块被包装成NIO Buffer对象,并提供了一系列的方法来方便对这个内存块数据的操作。

Buffer基本用法

使用Buffer来读写数据基本上按照以下几个步骤来进行。

  1. 将数据写入到Buffer
  2. 调用buffer.flip()方法。
  3. 从buffer中读取数据。
  4. 调用buffer.clear()或buffer.compact()方法。

当你向Buffer中写入数据时,buffer会跟踪有多少数据已经写入。当需要读取数据时,你需要buffer.flip()方法将buffer从写模式切换到读模式。在读模式中,你可以读取所有已经写入到Buffer中的数据。

当你已经读完buffer中的数据,你需要清空buffer来保证buffer能够再次被写。清空buffer有两种方法:clear()方法和compat()方法。clear()方法会清空所有的buffer中的数据,compat()方法只会清空已经读过的数据,所有没有读过的数据会放到buffer的最前面,新写入的数据会追加到未读数据的后面。

这是一个Buffer使用的简单例子,包括write,flip,read和clear方法。

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

Buffer本质上是一个可以进行读写操作的内存区域。这块内存区域被包装成Java Buffer对象,它包含了一系列的方法来简化对内存数据块的操作。

一个Buffer包含三个主要属性必须要熟悉。

  • capacity
  • position
  • limit

position和limit所代表的意义跟Buffer的读写模式有关,capacity则跟读写模式无关。

下图说明的是capacity,position和limit在读写模式中所代表的意义。

Capacity

作为一个内存块,Buffer有固定的大小,叫做capacity。你最大只能写入capacity个bytes,longs,chars个数据到Buffer。一旦buffer满了,你必须清空它(从buffer中读取数据或调用clear方法)。

Position

当你向缓存中写入数据,position表示当前位置。初始的position为0,当一个byte,long等被写入到buffer中时,poistion会移动到下一个可写的数据单元。position的最大值为capacity-1。

从Buffer中读取数据也是从指定的position开始。当使用flip()方法将buffer的模式从写模式切换到读模式,position位置变为0。数据从position指定的位置开始读起,并移动到下一个可读的单元。

Limit

在写模式中,limit指定了有多少数据可以写入到buffer中。在写模式中,limit与capacity值相等。

当buffer切换到读模式时,limit指定了buffer中可读的数据的大小。因此,当buffer切换到读模式时,limit被设置为写模式时的position位置。换句话说,读的数据可达到写的数据一样。

Buffer类型

Java NIO中包含以下几种类型。

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

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

分配Buffer

在获得Buffer对象之前必须先分配。每一个Buffer类都有一个allcate()方法来实现。下面是一个ByteBuffer分配48个字节容量的buffer的例子。

ByteBuffer buf = ByteBuffer.allcate(48);
复制代码

下面是一个CharBuffer分配1024个字符的例子:

CharBuffer buf = CharBuffer.allcate(1024);
复制代码

向Buffer中写入数据

向Buffer中写入数据有两种方式: 1、通过Channel向Buffer中写入数据。 2、通过buffer.put()方法写入。 下面是一个通过Channel向Buffer中写入数据的例子。

int byteRead = inChannel.read(buf); // read into buffer
复制代码

下面是一个通过Buffer的put()方法写入数据的例子:

buf.put(127);
复制代码

put还有其他版本的方法。比方说,在指定的位置写入数据,向buffer中写入一个数组。更多实现细节参考JavaDoc。

flip()

flip()将buffer从写模式切换到读模式。调用flip()方法将position重置为0,并将limit设置为原来position原来的位置。

换句话说,position表示当前读的位置,limit表示目前可读的数据。

从Buffer中读取数据

从Buffer中读取数据有两种方式

  1. 将Buffer中的数据读入到Channel。
  2. 通过Buffer的get()方法读取。

下面是一个将数据从Buffer读取到Channel中的例子。

// read from buffer into channel
int byteWritten = inChannel.write(buffer);
复制代码

下面是一个通过Buffer的get方法读取数据的例子

byte aByte = buf.get();
复制代码

get方法还有很多其他的版本。例如,从指定的位置开始读,从buffer中读取一个数组。更多实现细节参考JavaDoc。

rewind()方法

Buffer.rewind()方法将position重置为0,因此,可以从头开始读取Buffer中的数据。limit的值保持不变,仍然表示最多可读取的数据量。

clear()和compat()方法

一旦完成从Buffer中读取数据,需要让Buffer准备好再次写入,可以通过clear()方法和compat()方法来完成。

如果调用的是clear()方法,position会重置为0,并且limit重置为capacity的值。换句话说,Buffer被清空了。Buffer中的数据并没有被清空,只是这些标记告诉我们从哪里开始可以写入数据。

当Buffer中还剩下一些未读取的数据时调用了clear()方法,这些数据将会被忽略。这意味着不再有任何标记告诉我们哪些数据已经读取过了,哪些数据还未读取过。

如果Buffer中仍有未读的数据,且后续还需要这些数据,但是此时想要先先写些数据,那么使用compact()方法。

compact()方法将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。limit属性依然像clear()方法一样,设置成capacity。现在Buffer准备好写数据了,但是不会覆盖未读的数据。

mark方法与reset方法

通过调用Buffer.mark()方法可以标记一个指定的位置。通过Buffer的reset()方法可以回到原来mark时的position位置,下面是一个例子:

buffer.mark();
// call buffer.get() a couple of times. 
buffer.reset();
复制代码

equals方法和compareTo方法

可以通过equals方法和compareTo方法来比较两个buffer。

equals方法

  1. 有相同的类型(byte、char、int等)。
  2. Buffer中剩余的byte、char等的个数相等。
  3. Buffer中所有剩余的byte、char等都相同。

正如你所见,equals仅比较了Buffer中的部分数据,而不是Buffer中的每一个元素。事实上,它仅仅比较了剩余的元素。

compareTo方法

compareTo()方法比较两个Buffer的剩余元素(byte、char等), 如果满足下列条件,则认为一个Buffer“小于”另一个Buffer:

  1. 第一个不相等的元素小于另一个Buffer中对应的元素 。
  2. 所有元素都相等,但第一个Buffer比另一个先耗尽(第一个Buffer的元素个数比另一个少)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值