Java 杂谈java

第三节 netty前传-NIO中缓冲buffer-01

2018-10-16  本文已影响0人  勃列日涅夫

Buffers

缓冲区(Buffers)本质上是一个可以写入数据的内存块,然后可以读取。 这个内存块包含在NIO Buffer对象中,该对象提供了一组api,这样可以方便用户更轻松地使用内存块。

在NIO中已实现的buffer类中继承Buffer这个抽象类

public abstract class Buffer {
    // Cached unsafe-access object
    static final Unsafe UNSAFE = Unsafe.getUnsafe();
    /**
     * The characteristics of Spliterators that traverse and split elements
     * maintained in Buffers.
     */
    static final int SPLITERATOR_CHARACTERISTICS =
        Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED;

    // Invariants: mark <= position <= limit <= capacity
    private int mark = -1;
    private int position = 0;
    private int limit;
    private int capacity;
//略。。。
}

其他具体的实现方式,根据不同的需求实现例如
ByteBuffer底层使用的为byte数组
CharBuffer使用char数组
DirectByteBuffer使用直接内存,这里通过从抽象类中的Unsafe 类分配直接内存使用。

  1. 向buffer写入数据
  2. 调用buffer.flip() 方法反转
  3. 读取buffer中的数据
  4. 调用buffer.clear() 或者buffer.compact()清楚

当数据写入缓冲区时,缓冲区会跟踪写入的数据量(在buffer对象中有position 会跟踪写入点)。 一旦需要读取数据,就需要使用flip() 方法调用将缓冲区从写入模式切换到读模式。 在读模式下,缓冲区允许读取已经写入缓冲区的所有数据。一旦读完所有数据,需要清除缓冲区,以便再次写入。 可以通过两种方式执行:调用clear()或调用compact() 方法。 clear() 方法清除整个缓冲区。 compact()方法仅清除已读取的数据。 任何还没读的数据都会移动到缓冲区的开头,接下来写入时,就会在这些未读数据之后写入。
下面用一个简单的例子来说明

public class ReadFile {
    public static void main(String[] args){
        readFile();
    }
    public static void readFile(){
        try(RandomAccessFile randomAccessFile =
                    new RandomAccessFile("F:\\data\\test.txt","rw")){
            //获取连接通道
            FileChannel fileChannel = randomAccessFile.getChannel();
            //初始化一个缓冲区,大小为1024byte
            ByteBuffer buf = ByteBuffer.allocate(1024);
            //fileChannel.read(buf)从通道中读取文件的数据放入缓冲区,返回结构为读取的字节数
            //注意:这个方法会记录读取的位置,所以后续读取不会从头开始读取
            int bytesRead = fileChannel.read(buf);
            System.out.println(bytesRead);
            //读取到数据
            while(bytesRead != -1)
            {
                //反转后为可以读取缓冲中的数据
                buf.flip();
                while(buf.hasRemaining())//position < limit;表示可读
                {
                    //读取
                    System.out.print((char)buf.get());
                }
                //没有可读数据后,清除已读数据,从未读数据之后开始写入
                buf.compact();
                //开始继续读取
                bytesRead = fileChannel.read(buf);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

说明Buffer 中的Capacity, Position 和Limit之间的关系

如下图分别表示写入和读取操作的buffer


图片.png

关于Buffer中方法下一节详解

上一篇 下一篇

猜你喜欢

热点阅读