Java NIO 缓冲区

Java NIO中的Buffer及其子类用来跟Channel以及子类交互。如你所了解的,数据通过通道写入缓冲区,或者从缓冲区读取。

一个Buffer基本上就是一块你可以读写数据的内存。这块内存被包装成了Buffer对象,并且提供了一系列方法帮助你更好的操作这块内存。

Buffer的基本用法

使用Buffer读取数据通常分为如下4步:

  1. 将数据写入Buffer
  2. 调用buffer.flip()
  3. 从缓冲区读取数据
  4. 调用buffer.clear()或buffer.compact()

当你想Buffer中写入数据时,这块buffer会记录你写入了多少数据。当你需要读取数据的时候,你需要调用flip()方法将buffer从写模式切换到读模式。在写模式下,你可以读取你写入的所有数据。

当你读取完数据,你需要清空buffer,准备再次写入数据。你可以通过调用flip()或者compact(0方法来达到此目的。clear()方法用于清空整个缓冲区。compact()仅清空你已经读取的数据,所有未读的数据会被移动到缓冲区的开头,再次写入会被追加到这些未读数据的后面。

下面是使用Buffer的一个简单示例

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * Created by zk on 2014/12/26.
 */
public class FileChannelDemo {
    public static void main(String[] args) {
        try {
            RandomAccessFile aFile = new RandomAccessFile("G:\\test.txt", "rw");
            //IO <-> NIO
            FileChannel inChannel = aFile.getChannel();

            ByteBuffer buf = ByteBuffer.allocate(48);

            int bytesRead = inChannel.read(buf);
            while (bytesRead != -1) {
                System.out.println("[--Read--" + bytesRead + "]");
                buf.flip();

                //如果缓冲区中还有未读完的数据
                while (buf.hasRemaining()) {
                    System.out.print((char) buf.get());
                }

                buf.clear();
                bytesRead = inChannel.read(buf);
            }
            aFile.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

Buffer Capacity,Position and Limit

一个buffer通常是你可以读写数据的一块内存。这块内存被包装成了Buffer对象,并且提供了一系列方法让我们方面的去操作这块内存。
为了理解Buffer是如何工作的俄,你需要了解Buffer的三个属性,它们是:
  • capacity
  • position
  • limit
position和limit的意义取决于Buffer处于读模式还是写模式。capacity总是不变的,与Buffer所处模式无关。
Buffer Capacity,position and limit in write and read mode

Capacity

分配一片内存区域,其对应的Buffer总有固定的大小,也被称为Capacity。你可以往这片内存区域写入Capacity大小的bytes,longs,chars等等不同类型的数据。一旦缓冲区满,你必须置空这块缓冲区(read()或者clear())才能再次写入数据。

Position
当你向Buffer中写入数据时,你处在某一个位置。初始位置为0,。当一个byte,long等写入缓冲区,position指向下一个要插入数据的位置,position的最大值为capacity-1。
当你从缓冲区读取数据的时候也要从一个给定的位置开始。当你调用flip()将缓冲区从写模式切换到读模式,position的值被置为0。当你从缓冲区读取的数据的时候,position被指向到下一个可读数据的位置。


Limit

在写模式下,一个Buffer的limit是你可以写入数据的上限。在写模式下,这个limit等同于这个Buffer的容量(capacity)。
当你回绕(flip)这个Buffer到读模式下,limit意味着你可以读取多少数据。因此,当你将一个Buffer回绕(flip)到读模式,limit被置为写模式下position的值。换句话说,你可以读取你写入的所有数据。

Buffer类型

Java NIO包含以下几种Buffer类型:

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

如你所看到的,这些类型代表了不同的数据类型。或者说,这允许你使用char,short,int,long,float或者double来代替byte处理缓冲区数据。

MappedByteBuffer有一点不同,我们将单独说明。

分配一个缓冲区

要获得一个Buffer你必须先分配它。每一个Buffer类都有一个allocate()方法来完成这件事。
利用下面的代码,我们可以分配一个容量为48个字节的字节缓冲区:
ByteBuffer buf = ByteBuffer.allocate(48);
利用下面的代码,我们可以分配一个容量为1024个字符的字符缓冲区:
CharBuffer buf = CharBuffer.allocate(1024);

向缓冲区写入数据


你可以通过两种方式向缓冲区写入数据:
通过Channel向缓冲区写入数据
利用缓冲区自身调用put()方法
利用下面代码,我们可以利用Channel向缓冲区写入数据:
int bytesRead = inChannel.read(buf);
利用下面代码,我们可以通过put()方法向缓冲区写入数据:
buf.put(127);
put()方法还存在很多重载形式,允许你通过多种方式向缓冲区写入数据。例如,向指定位置或者将一个数组写入到缓冲区。更多的细节,可以参考Java 文档。

flip()


flip()方法将缓冲区从写模式切换到读模式。调用flip()方法会将position置为0,limit置为写模式下position的值。

从缓冲区读取数据


你可以通过以下两种方式从缓冲区读取数据:
通过通道从缓冲区读取数据
通过get()方法从缓冲区读取数据
利用下面的代码,你可以利用Channel从缓冲区读取数据:
int bytesWritten = inChannel.write(buf);
利用下面的代码,你可以通过get()方法从缓冲区读取数据:
byte aByte = buf.get();
get ()方法还存在很多重载形式,允许你通过多种方式缓冲区读取 数据。例如,指定位置读取 或者将数据读取到一个数组 。更多的细节,可以参考Java 文档。

rewind()


Buffer.rewind()将position置为0。因此你可以读取缓冲区中的所有数据。limit保持不变,标识了你可以从缓冲区读取多少数据。

clear() 和 compact()


当你从缓冲区读取完数据后,你需要缓冲区准备再次写入数据,这时你可以调用clear()或者compact()方法。
如果你调用clear(0方法,position的值被置为0,limit的值为置为capacity的值。或者说,缓冲区被清空。不过缓冲区中的数据并没有被清除。只有标志可以告诉你你可以往这片缓冲区的哪里写入数据。
如果当你调用clear()方法时,缓冲区中还存在未读的数据,这些数据将被忽略。
如果在缓冲区还用一些未读的数据,你想稍后读取。但是你需要在准备再次写入之前,调用compact()方法来代替clear()方法。
compact()将所有未读数据复制到缓冲区的开头。然后将position指向最后一个未读元素的右边,limit一样被置为capacity的值。这是缓冲区已经准备好再次写入数据,但是未读数据不会被覆盖掉。

mark() 和 reset()


你可以通过Buffer.mark()在缓冲区中标记一个给定的位置。然后你可以通过Buffer.reset()方法将position置为你曾经标记的位置。

equals() 和 compareTo()


我们可以通过equals()和compareTo()方法来比较两块缓冲区。
equals()
如果满足以下条件我们认为两块缓冲区是相等的:
  1. They are of the same type
  2. They have the same amount of remaining bytes,chars etc. int the buffer
  3. All remaining bytes,chars etc. are equal.
compareTo()
compareTo()比较两块缓冲区剩余的元素。
一个缓冲区被认为"smaller“另一个缓冲区,如果:
  1. The first element which is equal to the corresponding element int the other buffer, is smaller than that int the other buffer.
  2. All elements are equal, but the first buffer runs out of elements before the second buffer does(it has fewer elements)
原文地址:http://tutorials.jenkov.com/java-nio/buffers.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值