前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java NIO-3.Buffer

Java NIO-3.Buffer

作者头像
悠扬前奏
发布2019-05-30 20:19:12
4160
发布2019-05-30 20:19:12
举报
文章被收录于专栏:悠扬前奏的博客

Java NIO Buffers用来和NIO Channels交互。正如前文所述,数据从通道中读到缓冲区,或者从缓冲区写到通道。 缓冲区本质上是一块能写入数据,并延迟读取的内存。这块内存被包装成一个NIO Buffer类,并提供了一组方法简化对它的访问。

Buffer的基本用法

对Buffer的读写一般遵循以下四个步骤:

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

向缓冲区写入数据时,缓冲区记录写入了多少数据。一旦要读取数据,需要调用flip()方法将缓冲区从写模式转换到读模式。在读模式下,可以读取到之前写入缓冲区的数据。

完成数据读取后,需要清空缓冲区,让它可以再次被写入。有两种方式能够清空缓冲区:调用clear()方法或者compact()方法。clear()方法清空整个缓冲区。compact()方法仅清空已经读取的部分。所有未读取的数据被移动到缓冲区的开头。新数据将从未读取数据的后面开始写入。

以下是一个使用Buffer的简单实例,注意其中的write,flip,read,clear操作(原文中意为这四个操作用黑体标识,但是简书不支持)。

代码语言:javascript
复制
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,和Limit

缓冲区本质上是一块可以写入数据,然后从中读取的内存。这块内存被包装成一个NIO Buffer对象,提供了一组方法用来简化对内存的访问。 为了了解Buffer的工作原理,需要熟悉它的三个属性:

  • capacity
  • position
  • limit position和limit的含义取决于Buffer处在读膜还是还是写模式。capacity的含义是不变的。 以下是一个关于capacity,position,limit在读写模式中的插图,详细的解释在插图后面:

Buffer capacity,postion and limit in write and read mode

Capacity

作为一个内存块,Buffer有固定的大小,叫做"capacity(容量)"。只能往里面写入capacity个bytes,long,chars等类型。一旦Buffer满了,需要清空它才能继续往里面写入数据。

Position

数据写入Buffer中时,需要知道一个确切的位置。初始位置是0,当一个byte,long等数据写入后,position移动到buffer中的下一个插入数据的位置。position最大可为capacity-1. 从buffer读取数据时,也需要从某个特定的位置读。当buffer被从写模式flip成读模式时,position重置为0.当从Buffer中读数据时,就从position开始,然后position往后移动到下一个读的位置。

Limit

在写模式中,Buffer的Limit是对能写入多少数据的限制。写模式中limit等于Buffer的容量(capacity) 当把Buffer 转换到读模式后,limit代表能从buffer中读取多少数据。所以,buffer转换到读模式时,limit被设定为写模式中写入的位置。也就是说,能从buffer中读取的字节数就等于它被写入的字节数(limit被设定为写入的字节数,在写模式中就是position。)

Buffer Types

Java NIO 中有以下Buffer类型:

  • ByteBuffer
  • MappedByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer 可以看到,这些Buffer类型代表了不同的数据类型。换句话说,可以通过char,short,int,long,float或者double来操作buffer中的字节。

Buffer的分配

为了获得一个Buffer对象,需要先对它进行分配(allocate),每一个Buffer对象都有allocate()方法来完成这个工作。 例,分配了容量为48字节的ByteBuffer:

代码语言:javascript
复制
ByteBuffer buf = ByteBuffer.allocate(48);

例,分配容量为1024个字符的CharBuffer:

代码语言:javascript
复制
CharBuffer buf = CharBuffer.allocate(1024);

向Buffer中写

向Buffer中写入数据有两种方法:

  1. 从Channel中写到Buffer
  2. 通过缓冲区的put()方法写入数据。 例,从Channel写到Buffer:
代码语言:javascript
复制
int byteRead = inChannel.read(buf);// read into a buffer

例,通过put方法写入:

代码语言:javascript
复制
buf.put(127)

put方法有很多不同的版本,提供了数据写入buffer的不同方式。例如,在指定的位置写入,或者写入字节数组。更多关于缓冲区的细节可以参考JavaDoc。

flip()

flip()方法将Buffer从写模式转换到读模式。调用flip()会将position重置为0,将limit设置为刚才的position。 换句话说,position现在标记了读的位置,limit标记了有多少字节,字符等被写入到了buffer——也就是有多少字节,字符可以被读取。

从Buffer中读

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

  1. 从缓冲区读取数据到通道。
  2. 用get()方法从缓冲区中读取数据 例,从缓冲区中读到通道
代码语言:javascript
复制
// read from buffer into channel
int bytesWritten = inChannel.write(buf);

例,用get()方法从Buffer中读:

代码语言:javascript
复制
byte aByte = buf.get();

get()方法有很多版本,提供了从Buffer读取数据的不同方式。例如,从指定的位置读取,或者读取字节数据。更多关于缓冲区的细节可以参考JavaDoc。

rewind()

Buffer.rewind()方法将position重置为0。这样能够重读buffer中数据。limit保持不变,仍然表示能够从buffer中读取的数据量。

clear()和compact()

一旦读取完Buffer中的数据,需要让Buffer做好再次写入的准备。 可以通过调用clear()或者compact()方法实现。 clear()方法会将position重置为0,limit重置为capacity。也就是说,Buffer被清空了。Buffer中的数据并未清除,只有这些标记代表Buffer能被写入数据的位置。 如果Buffer中仍有未被读取的数据,clear()方法将导致它们被遗忘,这意味着不再有任何标记表明那些数据被读取了,哪些没有。 如果Buffer中仍然有未被读取的数据,且后续还需要读取它们,但此时需要先写入数据。就需要使用compact()方法代替clear()方法。 compact()将未读取的数据复制到Buffer 的开头,然后将position设置为最后一个未读元素的后面,limit属性和clear()方法一样,被设置为capacity。之后就可以往Buffer中写入数据了,并且不会覆盖未读数据。

mark()和reset()

可以通过调用Buffer.mark()方法在Buffer中标记一个指定的位置。之后可以通过Buffer.reset()方法恢复到这个位置。 例如:

代码语言:javascript
复制
buffer.mark();
// call buffer.get() a couple of time, e.g. during parsing.
buffer.reset;// set position back to mark
equals() 和compareTo()

使用equals()和compareTo()方法可以比较两个缓冲区。

equals()

满足一下条件,判断两个缓冲区相等:

  • 类型相同(byte,char,int等)
  • 剩余字节,字符等数量相同,
  • 所有剩余的字节,字符相同 尅建,equals仅仅比较了Buffer中的部分数据,而不是其中的每一个元素,实际上,仅仅比较了Buffer中的剩余数据。
compareTo()

compareTo()方法比较了两个缓冲区中的剩余数据,在例如排序等需求中。如果满足一下条件,一个Buffer被认为小于另一个:

  1. 第一个不相等的元素小于另一个buffer中的对应元素(原文有误)。
  2. 所以的元素相等,但是第一个Buffer比另一个先耗尽(第一个Buffer的元素更少)。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.06.02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Buffer的基本用法
  • Buffer的Capacity,Position,和Limit
  • Capacity
  • Position
  • Limit
  • Buffer Types
  • Buffer的分配
  • 向Buffer中写
    • flip()
    • 从Buffer中读
    • rewind()
    • clear()和compact()
    • mark()和reset()
      • equals() 和compareTo()
        • equals()
      • compareTo()
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档