capacity-1
Java NIO Buffers用于和NIO Channel交互。 我们从Channel中读取数据到buffers里,从Buffer把数据写入到Channels。Buffer本质上就是一块内存区,可以用来写入数据,并在稍后读取出来。这块内存被NIO Buffer包裹起来,对外提供一系列的读写方便开发的接口。java中java.nio.Buffer的常见实现类如下,不过我们这里只说一下ByteBuffer这个实现。
java.nio.Buffer
ByteBuffer
Buffer缓冲区实质上就是一块内存,用于写入数据,也供后续再次读取数据,为了便于理解,你可以把它理解为一个字节数组。它有有四个重要属性:
public abstract class Buffer { // Invariants: mark <= position <= limit <= capacity private int mark = -1; private int position = 0; private int limit; private int capacity; }
capacity
position
下一个要读写的元素位置(从0开始),当使用buffer的相对位置进行读/写操作时,读/写会从这个下标进行,并在操作完成后,buffer会更新下标的值。
limit
在Buffer上进行的读写操作都不能越过这个limit。
mark
mark()
reset()
注:
这些属性总是满足以下条件:
0 <= mark <= position <= limit <= capacity
通过上面的描述可以看出,其中position和limit的具体含义取决于当前buffer的模式(读模式还是写模式)。capacity在两种模式下都表示容量。
HeapByteBuffer
DirectByteBuffer
hasarray
例如:ByteBuffer.allowcate(10); 内容:[0 ,1 ,2 ,3 4, 5, 6, 7, 8, 9] ## compact前 [0 ,1 ,2 , 3, 4, 5, 6, 7, 8, 9] pos=4 lim=10 cap=10 ## compact后 [4, 5, 6, 7, 8, 9, 6, 7, 8, 9] pos=6 lim=10 cap=10
创建ByteBuffer可以使用allocate或者wrap,就像下面这样:
需要注意的是:创建的缓冲区都是定长的,大小无法改变。若发现刚创建的缓冲区容量太小,只能重新创建一个合适的。
关于ByteBuffer wrap(byte[] array,int offset,int length)这个方法,这里再强调一下,这样创建的ByteBuffer的capacity和array的大小是一样的,buffer的position是offset, buffer的limit是offset+length,position之前和limit之后的数据依然可以访问到。例子如下:
ByteBuffer wrap(byte[] array,int offset,int length)
public class Demo { public static void main(String args[]){ byte arr[]=new byte[100]; ByteBuffer buffer=ByteBuffer.wrap(arr,3,25); System.out.println("Capacity is: "+buffer.capacity()); System.out.println("Position is: "+buffer.position()); System.out.println("limit is: "+buffer.limit()); } } //结果: Capacity is: 100 Position is: 3 limit is: 28
wrap只是简单地创建一个具有指向被包装数组的引用的缓冲区,该数组成为后援数组。对后援数组中的数据做的任何修改都将改变缓冲区中的数据,反之亦然。
public static void main(String args[]){ byte arr[]=new byte[100]; //将arr数组全部置为1 Arrays.fill(arr, (byte)1); ByteBuffer buffer=ByteBuffer.wrap(arr,3,25); //对后援数组中的数据做的任何修改都将改变缓冲区中的数据 arr[0]=(byte)2; buffer.position(0); System.out.println(buffer.get()); //在缓冲区上调用array()方法即可获得后援数组的引用。 System.out.println(Arrays.toString(buffer.array())); } //运行结果: 2 [2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ....]//总共100个元素
allocate则是创建了自己的后援数组,在缓冲区上调用array()方法也可获得后援数组的引用。通过调用arrayOffset()方法,可以获取缓冲区中第一个元素在后援数组的偏移量。但是使用wrap创建的ByteBuffer,调用arrayOffset永远是0。
public static void main(String args[]){ ByteBuffer buffer=ByteBuffer.allocate(100); //对后援素组的修改也可以反映到buffer上 byte arr[]=buffer.array(); arr[1]=(byte)'a'; buffer.getInt(); System.out.println(Arrays.toString(buffer.array())); System.out.println(buffer.arrayOffset()); } //运行结果: [0, 97, 0, 0, 0, 0, 0, 0,...]//总共100个元素 0
通过ByteBuffer allocateDirect(int capacity)创建的叫直接缓冲区,使用的堆外内存。可以通过isDirect()方法查看一个缓冲区是否是直接缓冲区。由于直接缓冲区是没有后援数组的,所以在其上面调用array()或arrayOffset()都会抛出UnsupportedOperationException异常。注意有些平台或JVM可能不支持这个创建直接缓冲区。
ByteBuffer allocateDirect(int capacity)
isDirect()
写模式下,往buffer里写一个字节,并把postion移动一位。写模式下,一般limit与capacity相等。
写完数据,需要开始读的时候,将postion复位到0,并将limit设为当前postion。
从buffer里读一个字节,并把postion移动一位。上限是limit,即写入数据的最后位置。
将position置为0,并不清除buffer内容。
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class Demo { private static final int SIZE = 1024; public static void main(String[] args) throws Exception { // 获取通道,该通道允许写操作 FileChannel fc = new FileOutputStream("data.txt").getChannel(); // 将字节数组包装到缓冲区中 fc.write(ByteBuffer.wrap("Some text".getBytes())); // 关闭通道 fc.close(); // 随机读写文件流创建的管道 fc = new RandomAccessFile("data.txt", "rw").getChannel(); // fc.position()计算从文件的开始到当前位置之间的字节数 System.out.println("此通道的文件位置:" + fc.position()); // 设置此通道的文件位置,fc.size()此通道的文件的当前大小,该条语句执行后,通道位置处于文件的末尾 fc.position(fc.size()); // 在文件末尾写入字节 fc.write(ByteBuffer.wrap("Some more".getBytes())); fc.close(); // 用通道读取文件 fc = new FileInputStream("data.txt").getChannel(); ByteBuffer buffer = ByteBuffer.allocate(SIZE); // 将文件内容读到指定的缓冲区中 fc.read(buffer); //此行语句一定要有, 如果没有,就是从文件最后开始读取的,当然读出来的都是byte=0时候的字符。通过buffer.flip();这个语句,就能把buffer的当前位置更改为buffer缓冲区的第一个位置 buffer.flip(); while (buffer.hasRemaining()) { System.out.print((char)buffer.get()); } fc.close(); } }
java.nio.ByteBuffer介绍到这里更多关于java学习请参考编程字典java教程和问答部分,谢谢大家对编程字典的支持。
原文链接:https://codingdict.com/