Java NIO

来源:互联网 发布:解码矩阵 编辑:程序博客网 时间:2024/06/06 12:43

一、Buffer基础知识

JAVA NIO中的Buffer用于和NIO通道进行交互,数据从通道读入缓存区,从缓存区写入通道。

缓冲区本质上是一块可以写入数据,也可以读出数据的内存,这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的调用该块内存。

二、Buffer的基本用法

1、使用Buffer读写数据一般有四种个步骤:

  1. 写入数据到Buffer,Buffer会记录写入了多少数据。
  2. 调用flip()方法,将Buffer从写模式转换为读模式。
  3. 从Buffer中读取数据。
  4. 调用clear()方法或compact()方法。clear()方法会清空缓存区所有的数据,compact()方法只会清除已经读取的数据。

任何未读的数据都会被放到缓存区的起始处,新写入的数据放到缓存区未读取数据的后面。



2、buffer的capacity、position和limit

理解Buffer的工作原理,需要熟悉它的三个属性:capacity、position、limit。

position和limit的含义取决于Buffer处于读模式还是写模式,但capacity的含义一直不变。
capacity:作为一个内存块,Buffer有一个固定的大小,”capacity”。
limit:Buffer在不同的模式下,可以写入或读取数据的多少。但一般情况下,limit都会被设置为之前position的值。
position:当你写入或读取Buffer时,position表示当前的位置,每一次Buffer转换模式时,position都会被初始化为0,position的最大值为capacity-1。

准确理解capacity、position、limit所代表的意义对于理解Buffer有很大的帮助。



3、Buffer的类型

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

这里包含了常见的数据类型,也有map类型的数据。


4、Buffer的分配

要想获得一个Buffef对象,首先要对对象进行分配,每一个Buffer类都有一个allocate()方法,用于分配不同的字节给Buffer。

ByteBuffer buf = ByteBuffer.allocate(1024);//创建一个Buffer,状态为写入状态


5、flip()方法

flip()方法将Buffer从写模式转换为读模式。
调用flip()方法会将position设置为0,并将limit设置为之前position的值。

buf.flip();//反转Buffer,将写入状态转换为写出状态


6、rewind()方法

rewind()方法将position设置为0,所以可以重读Buffer中的所有数据,并且返回一个Buffer。

 out.write(buf);    // Buffer中写入数据 buf.rewind();      // 重绕缓冲区Buffer  buf.get(array);    // Buffer中的数据被替换到array


7、clear()方法和compact()方法

当读取完Buffer中的数据,需要让Buffer准备好再次被写入,可以调用clear()和compact()方法实现。

clear()方法会将position被设置为0,limit被设置为capacity的值。此时Buffer被清空,然后Buffer中的数据并未清除,只是告诉我们该从哪里写入数据。

compact()方法会将所有未读的数据拷贝到Buffer起始处,然后将position设到最后一个未读元素的后面,limit依旧被设置为capacity,现在Buffer写入数据就不会覆盖未读的数据了。

buf.clear();//将Buffer清空,以便下次写入

当你读过源码你就会知道,此方法不能实际清除缓冲区中的数据,但从名称来看它似乎能够这样做,这样命名是因为它多数情况下确实是在清除数据时使用。



8、mark()方法和reset()方法

调用mark()方法可以标记一个特定的position,之后可以通过reset()方法恢复到这个position。

两者的返回值都为Buffer,而且被标记之前的position并不会被丢弃。



9、equals()和compareTo()方法

使用equals()和conoareTo()比较两个Buffer对象

对于equals()方法,当满足下列条件时,两个Buffer相等:

  1. 相同的类型。
  2. Buffer中剩余的byte、char等的个数相等。
  3. Buffer中所有的剩余的byte、char等都相同。
  4. 返回值:相同时为true,其余为false。

equals()只比较Buffer的一部分,不是每一个在它的元素都比较,实际上,它只比较Buffer中剩余的元素。

compareTo()只比较Buffer的剩余元素byte、char
若满足下列条件,认为一个Buffer小于另一个Buffer:

  1. 第一个不相等的元素小于另外一个Buffer中对应的元素。
  2. 比较两个字节缓冲区的方法是按字典顺序比较它们的剩余元素序列,而不考虑每个序列在其对应缓冲区中的起始位置。
  3. 返回值:正整数、负整数和零。

注:剩余元素是从position到limit之间的元素。


三、Demo

package com.vgbh;import java.io.FileNotFoundException;import java.io.IOException;import java.io.RandomAccessFile;import java.nio.ByteBuffer;import java.nio.channels.FileChannel;public class ChannelDemo {    public void readFromChannelFile () {        try {            RandomAccessFile file = new RandomAccessFile("F:/WorkSpace/TestBook.txt", "rw");//IO的获取文件类            FileChannel fileChannel = file.getChannel();            ByteBuffer buf = ByteBuffer.allocate(1024);//创建一个Buffer,状态为写入状态            int byteReads = fileChannel.read(buf);//当前buf中的数据长度            while (byteReads != -1) {                System.out.println("ssss   " + byteReads + "   ssss");                buf.flip();//反转Buffer,将写入状态转换为写出状态                while (buf.hasRemaining()) {                    System.out.print((char)buf.get());//获取buf中的数据,将int转换为char,在buf写完后会自动转换为写入状态                }                buf.clear();//将Buffer清空,以便下次写入                byteReads = fileChannel.read(buf);//重新写入新的数据            }            file.close();        } catch (FileNotFoundException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }    }}

上边的代码只是一个小Demo,有兴趣的可以将其应用到实践中去。
推荐大家可以去看看Java的API文档,有很大的帮助。

有问题的可以联系我的邮箱。