在NIO库中,所有数据都是用缓冲区处理的。每一个java基本类型都提供了对应的缓冲区类型,并且每个缓冲类型都是继承Buffer接口的一个实例。除了ByteBuffer以外,其他缓冲类型都提供了完全一样的操作。

下面我们通过ByteBuffer的内部细节来了解,缓冲类型的操作与转换。

ByteBuffer状态变量:

position、limit、capacity这三个值制定了缓冲区在任意时刻的状态。

position:用来跟踪已经写了多少数据,他指定了下一个字节将放到数组的那一个元素中。例如,如果你要你从通道中读三个字节到缓冲区中,那么缓冲区的position将会设置为3,指向数组中第四个元素。同样在写入通道中,position值跟踪从缓冲区中获取了多少数据,它指定了下一个字节来自数组的那一个元素。

limit:表面了缓冲区还有多少数据需要取出,或者还有多少空间可以放入数据。

capacity:表明了可以存储在缓冲区中最大数据容量。

ByteBuffer方法介绍:

一、状态控制

flip():这个方法首先他将limit设置为当前position,然后他将position设置为0。这意味着当使用了flip方法后我们可以获得position为0,limit为写入数据的长度的所有字节,即以写入到缓冲区中的所有字节数据。

clear():这个方法重设缓冲区以便接受更多的字节,他将limit设置为相同capacity,并将position设置为0,当调用了clear后,缓冲区可以接受新的数据了。

二、访问方法

get():从缓冲中读取字节,当入参为byte数组时,表示将缓冲中数据写入到指定长度的字节数组中。当进行读操作的时候,状态变量position会自动进位;

put():将字节放入到缓冲区中。

除了上面两个读写方法外,ByteBuffer还提供了对不同基本类型的值读写操作方法。例如:getByte(),getChar(),getLong(),putDouble(),putChar()....

在文件通道中(FileChannel)提供了read(),write(),通过clear()和flip()进行缓冲区在读写之间切换,简化了文件对缓冲区的读写操作。

例:实现将文件中内容写入到另外一个文件中去

  1. while(true){  
  2.   buffer.clear();  
  3.   int r = fileChannelIn.read(buffer);  
  4.   if(r==-1) break;  
  5.   buffler.flip();  
  6.   fileChannelOut.write(buffer);  

三、 缓冲区分配和包装

缓冲区分配:在能够读和写之前,必须有一个缓冲区。要创建缓冲区,你必须分配它。静态方法allocate()实现了分配一个具有指定大小的底层数组,并将它包装到一个缓冲区对象中。

例:此实例实现了将一个float类型转换为byte数组的操作。

  1. float v=12.11;
  2. ByteBuffer bb = ByteBuffer.allocate(4);
  3. byte[] ret = new byte[4];
  4. FloatBuffer fb = bb.asFloatBuffer();
  5. fb.put(v);
  6. bb.get(ret);
  7. return ret;

 包装:你还可以将一个现有的数组转换为缓冲区。使用wrap()方法将一个数组包装为缓冲区,必须非常小心地进行这类操作,应为一旦完成包装,底层数据就可以通过缓冲区或者直接访问。

例:这个实例实现了将一个byte数组转换为float类型的数据

  1. byte[] v;
  2. ByteBuffer bb = ByteBuffer.wrap(v);
  3. FloatBuffer fb = bb.asFloatBuffer();
  4. return fb.get();

五、缓存区分片

slice()方法可以根据现有的缓冲区创建一个新的缓冲区,新缓冲区共享与原来的缓冲区的一部分数据。

五、字符集(编码/解码)

Charset是“十六位Unicode字符串序列与字节序列之间的一个命名映射”。他可以帮助你尽可能移植读写字符串序列。下面我们将介绍如何使用Charset来处理现代文本格式的方式处理文本数据。

1、编码(CharsetDecoder):用于将逐位表示的一串字符转换为具体的char值。

2、解码(CharsetEncoder):用于将字符转换回位。

以下示例,演示了如何将读入的文本,进行编码返回为字符串:

  1. file = new FileInputStream("TT.TXT");
  2. FileChannel fc = file.getChannel();
  3. ByteBuffer buffer = ByteBuffer.allocate(5000);
  4. fc.read(buffer);
     
  5. buffer.flip();
  6. try{
  7. Charset charset = Charset.forName("gb2312");
  8. CharsetDecoder decoder = charset.newDecoder();
  9. CharBuffer charBuffer = decoder.decode(buffer);
  10. return charBuffer.toString();
  11. } catch (Exception ex){
  12. ex.printStackTrace();
  13. return "" ;
  14. }