javaNIO学习笔记之缓冲区Buffer

原创 2016年06月02日 10:20:35

缓冲区的基类:Buffer

Buffer有四个属性:
1、capacit(容量)
2、limit(上界)
3、position(位置)
4、mark(标记)

*:绝对存储不会影响缓冲区的位置属性

存和取的方法:

public abstract byte get( );
 public abstract byte get (int index); 
 public abstract ByteBuffer put (byte b); 
 public abstract ByteBuffer put (int index, byte b);  

Get和put可以是相对的或者是绝对的。在前面的程序列表中,相对方案是不带有索引参数的函数。当相对函数被调用时,位置在返回时前进一。如果位置前进过多,相对运算就会抛出异常。对于put(),如果运算会导致位置超出上界,就会抛出BufferOverflowException异常。对于get(),如果位置不小于上界,就会抛出BufferUnderflowException异常。绝对存取不会影响缓冲区的位置属性,但是如果您所提供的索引超出范围(负数或不小于上界),也将抛出IndexOutOfBoundsException异常。
翻转:
Buffer.flip()
这是一个封装好了的函数,它的功能与下面函数执行的功能是等效的
buffer.limit(buffer.position()).position(0)
这样做的目的是:当你对一个缓冲区装载完毕时,你需要改变它的位置状态让它准备好被取出数据。所以我们把它的位置定位为0,上界定位为当前加载到的位置。
书本上的解释:
Flip()函数将一个能够继续添加数据元素的填充状态的缓冲区翻转成一个准备读出元素的释放状态。在翻转之后,图2.4的缓冲区会变成下图中的样子。
这里写图片描述
释放数据
在对数据释放前,一定要确保对缓冲区进行了一次翻转操作(并且只能有一次)
使用hasRemaining()函数可以判断是否达到缓冲区的上界。

 for (int i = 0; buffer.hasRemaining( ), i++) {
  myByteArray [i] = buffer.get( ); 
 }

我们也可以自己自己使用remaining()函数获得可读取的数据数自行循环

 int count = buffer.remaining( );
  for (int i = 0; i < count, i++) {
  myByteArray [i] = buffer.get( ); 
 }

如果您对缓冲区有专门的控制,这种方法会更高效,因为上界不会在每次循环重复时都被检查(这要求调用一个buffer样例程序)。上文中的第一个例子允许多线程同时从缓冲区释放元素。

*:缓冲区的存取不是线程安全的。使用多线程一定要进行同步

使用compact()函数可以压缩未读的缓冲区
以下是JDK API中的解释:
public abstract CharBuffer compact()压缩此缓冲区(可选操作)。
将缓冲区当前位置和界限之间的字符(如果有)复制到缓冲区的开始处。即将索引 p = position() 处的字符复制到索引 0 处,将索引 p + 1 处的字符复制到索引 1 处,依此类推,直到将索引 limit() - 1 处的字符复制到索引 n = limit() - 1 - p 处。然后将缓冲区的位置设置为 n+1,并将其界限设置为其容量。如果已定义了标记,则丢弃它。

将缓冲区的位置设置为复制的字符数,而不是零,以便调用此方法后可以紧接着调用另一个相对 put 方法。
书上解释:调用compact()的作用是丢弃已经释放的数据,保留未释放的数据,并使缓冲区对重新填充容量准备就绪。
如果您想在压缩后释放数据,缓冲区会像之前所讨论的那样需要被翻转。无论您之后是否要向缓冲区中添加新的数据,这一点都是必要的。
标记
这本章节的开头,我们已经涉及了缓冲区四种属性中的三种。第四种,标记,使缓冲区能够记住一个位置并在之后将其返回。缓冲区的标记在mark( )函数被调用之前是未定义的,调用时标记被设为当前位置的值。reset( )函数将位置设为当前的标记值。如果标记值未定义,调用reset( )将导致InvalidMarkException异常。一些缓冲区函数会抛弃已经设定的标记(rewind( ),clear( ),以及flip( )总是抛弃标记)。如果新设定的值比当前的标记小,调用limit( )或position( )带有索引参数的版本会抛弃标记。
缓冲区的比较
缓冲区之前可以使用equals()函数或compareTo()函数进行比较。
如果两个缓冲区中剩余的内容相同,那么equals()函数会返回true。
两个缓冲区相等的充要条件:

  • 两个对象类型相同。包含不同数据类型的buffer永远不会相等,而且buffer绝不会等于非buffer对象。

  • 两个对象都剩余同样数量的元素。Buffer的容量不需要相同,而且缓冲区中剩余数据的索引也不必相同。但每个缓冲区中剩余元素的数目(从位置到上界)必须相同。

  • 在每个缓冲区中应被Get()函数返回的剩余数据元素序列必须一致。

批量移动

public CharBuffer get (char [] dst) 
public CharBuffer get (char [] dst, int offset, int length) public final CharBuffer put (char[] src) 
public CharBuffer put (char [] src, int offset, int length) public CharBuffer put (CharBuffer src) 
public final CharBuffer put (String src) 
public CharBuffer put (String src, int start, int end)

批量传输的大小总是固定的。省略长度意味着整个数组会被填满。
如果缓冲区的长度没有指定数组的长度长,那么整个传输都会失败,并且会抛出一个BufferUnderflowException异常

缓冲区对象的创建

以CharBuffer为例。
1、使用静态函数allocate创建指定大小的缓冲区:

 CharBuffer charBuffer = CharBuffer.allocate (100);

2、使用静态函数warp将数组转化为Charbuffer,注意数组的类型必须和Buffer匹配

char [] myArray = new char [100];
CharBuffer charbuffer = CharBuffer.wrap (myArray);

warp还可加入两个参数分别作为position和limit
使用上两种方式创建的缓冲区通常都是间接的,间接的缓冲区使用备份数组,可以使用hasArray函数判断缓冲区是否有一个可存取的备份数组,使用array函数可以得到备份数组,任何对备份数组的更改都会映射到缓冲区

缓冲区的复制

以CharBuffer为例
API中提供了以下方法:

 public abstract CharBuffer duplicate( ); 
 public abstract CharBuffer asReadOnlyBuffer( ); 
 public abstract CharBuffer slice( );

duplicate函数创建了一个与原始缓冲区相似的缓冲区,每个缓冲区有自己的位置信息,但对缓冲区的修改都会映射到同一个底层数组上。
slice创建一个分割缓冲区:分割缓冲区与复制相似,但slice()创建一个从原始缓冲区的当前位置开始的新缓冲区,并且其容量是原始缓冲区的剩余元素数量(limit-position)。这个新缓冲区与原始缓冲区共享一段数据元素子序列。分割出来的缓冲区也会继承只读和直接属性。

字节缓冲区

关于字节存储顺序:
只有ByteBuffer的字符顺序设定可以随时通过调用以ByteOrder.BIG_ENDIAN或ByteOrder.LITTL_ENDIAN为参数的order()函数来改变。
如果一个缓冲区被创建为一个ByteBuffer对象的视图(参见2.4.3节),那么order()返回的数值就是视图被创建时其创建源头的ByteBuffer的字节顺序设定。视图的字节顺序设定在创建后不能被改变,而且如果原始的字节缓冲区的字节顺序在之后被改变,它也不会受到影响。。
直接缓冲区:
调用ByteBuffer.allocateDirect()函数产生
它直接与JVM低底层的IO交互,效率最高

字节缓冲区可以创建视图:

public abstract CharBuffer asCharBuffer(); public abstract ShortBuffer asShortBuffer(); public abstract IntBuffer asIntBuffer(); public abstract LongBuffer asLongBuffer(); public abstract FloatBuffer asFloatBuffer(); public abstract DoubleBuffer asDoubleBuffer();

ByteBuffer类提供了一个不太重要的机制来以多字节数据类型的形式存取byte数据组。ByteBuffer类为每一种原始数据类型提供了存取的和转化的方法:

public abstract class ByteBuffer extends Buffer implements Comparable {
 public abstract char getChar( ); 
 public abstract char getChar (int index);
 public abstract short getShort( ); 
 public abstract int getInt( ); 
 public abstract long getLong( ); 
 public abstract float getFloat (int index);    
 public abstract double getDouble( ); 
 public abstract double getDouble (int index); 
 public abstract ByteBuffer putChar (char value); 
 public abstract ByteBuffer putChar (int index, char value); 
 public abstract ByteBuffer putShort (short value); 
 public abstract ByteBuffer putShort (int index, short value); 
 public abstract ByteBuffer putInt (int value); 
 public abstract ByteBuffer putInt (int index, int value); 
 public abstract ByteBuffer putLong (long value); 
 public abstract ByteBuffer putLong (int index, long value); 
 public abstract ByteBuffer putFloat (float value); 
 public abstract ByteBuffer putFloat (int index, float value); 
 public abstract ByteBuffer putDouble (double value); 
 public abstract ByteBuffer putDouble (int index, double value); 
 }
版权声明:本文为博主原创文章,未经博主允许不得转载。

java NIO(七) 缓冲区——视图缓冲区

正如上一章节所说的,大多数的视图缓冲区都是字节缓冲区的视图; 本节我们用ByteBuffer举例; ByteBuffer有这么六个方法来创建对应的视图缓冲区: public abstract C...
  • u014783753
  • u014783753
  • 2015年02月09日 10:59
  • 544

JavaNIO之缓冲区(Buffers)

下面的例子来自于《Java I/O,NIO and NIO2》,阅读本书Buffers之后所作的代码笔记。 例1:Buffer的几个重要属性及修改 package chapter06; import...
  • BruceLeeNumberOne
  • BruceLeeNumberOne
  • 2017年06月28日 15:20
  • 71

【JAVA】【NIO】4、Java NIO Buffer

Java NIO的Buffer用于和channel进行交互。 buffer本质上是一个内存块,你可以写数据,然后读取出来。 这个内存块是通过NIO的Buffer对象进行包装的,该对象提供了一系列的...
  • chiweitree
  • chiweitree
  • 2015年03月16日 17:33
  • 1009

JavaNIO:Buffer

文章来源:http://blog.csdn.net/guoxilen/article/details/25511283和http://blog.csdn.net/guoxilen/article/de...
  • boonya
  • boonya
  • 2017年01月11日 14:54
  • 362

JavaNIO之缓冲区基础

该博客是《Java NIO》学习笔记中的缓冲区基础这一章节,由于内容很多,只记录代码和测试结果,不明白的地方请参见《Java NIO》一书,书中有详细的解释。 例子:填充和释放缓冲区 packag...
  • BruceLeeNumberOne
  • BruceLeeNumberOne
  • 2017年06月28日 14:28
  • 136

JavaNIO学习之Buffer

Java Buffer的学习Buffer,即缓冲区,它包含一些要写入或者要读取的数据。可以将其类比成数组来进行理解。下面介绍其特性及常用方法 属性 Buffer常用属性有位置,容量,限制,标记 ...
  • zyxwvuuvwxyz
  • zyxwvuuvwxyz
  • 2017年10月09日 18:30
  • 50

缓冲区(Buffer)

##1、 概念介绍 ## 缓冲区(Buffer)就是在内存中预留指定大小的存储空间用来对I/O的数据做临时存储,这部分预留的内存空间叫缓冲区。 使用缓冲区有两个好处: 1、减少实际物理读写次数...
  • guzhangyu12345
  • guzhangyu12345
  • 2017年06月08日 20:50
  • 524

NIO学习笔记之缓冲区Buffer

缓冲区的基类:BufferBuffer有四个属性: 1、capacit(容量) 2、limit(上界) 3、position(位置) 4、mark(标记)*:绝对存储不会影响缓冲区的位置属性存...
  • u013929852
  • u013929852
  • 2016年06月01日 14:20
  • 458

如何关闭 vim 的缓冲区

*22.4* 缓冲区列表 Vim 编辑器使用术语 "缓冲区" 来描述编辑当中的文件。实际上,缓冲区是你编辑的文件 的副本。你修改完缓冲区,就把缓冲区的内容写进文件。缓冲区不仅存放文件内容,而且...
  • FuDesign2008
  • FuDesign2008
  • 2012年02月26日 11:51
  • 7783

Node.js 之Buffer缓冲区

JavaScript 语言自身只有字符串数据类型,没有二进制数据类型。 但在处理像TCP流或文件流时,必须使用到二进制数据。因此Node.js中定义了Buffer类用来存放二进制数据的缓存区。如何创...
  • u014410695
  • u014410695
  • 2016年02月19日 14:57
  • 837
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:javaNIO学习笔记之缓冲区Buffer
举报原因:
原因补充:

(最多只允许输入30个字)