java NIO之buffer
Posted 爱上口袋的天空
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java NIO之buffer相关的知识,希望对你有一定的参考价值。
1、简介
- 通道进行交互。数据是从通道读入缓冲区,从缓冲区写入到通道中
- 在 NIO 库中,所有数据都是用缓冲区处理的
1.1、基本用法
使用 Buffer 读写数据,四个步骤:
- 写入数据到 Buffer
- 调用 flip()方法
- 从 Buffer 中读取数据
- 调用 clear()方法或者 compact()方法
读数据的完整例子
@Test public void buffer01() throws Exception { //FileChannel RandomAccessFile aFile = new RandomAccessFile("b://1.txt","rw"); FileChannel channel = aFile.getChannel(); //创建buffer大小 ByteBuffer buffer = ByteBuffer.allocate(1024); //读 int bytesRead = channel.read(buffer); while(bytesRead != -1) { //read模式 buffer.flip(); while(buffer.hasRemaining()) { System.out.println((char)buffer.get()); } buffer.clear(); bytesRead = channel.read(buffer); } aFile.close(); }
写数据的完整例子:
//创建buffer IntBuffer buffer = IntBuffer.allocate(8); //buffer放 for (int i = 0; i < buffer.capacity(); i++) { int j = 2*(i+1); buffer.put(j); } //重置缓冲区 buffer.flip(); //获取 while(buffer.hasRemaining()) { int value = buffer.get(); System.out.println(value+" "); }
1.2、三个重要属性
Buffer还有三个属性:Capacity、Position、limit
- capacity 内存块固定大小值
一旦 Buffer 满了,需要将其清空,才能写入- position
写入数据的时候,初始值为0,慢慢会往下移动,最大值为-1表示满了
读入数据的时候, position=2 时表示已开始读入了 3 个 byte。ByteBuffer.flip()切换到读模式时 position 会被重置为 0- limit
limit 表示可对 Buffer 最多写入或者读取多少个数据
1.3、方法详解
分配字节数据
要想获得一个 Buffer 对象首先要进行分配。 每一个 Buffer 类都有一个 allocate 方法
比如:ByteBuffer buf = ByteBuffer.allocate(48);
写数据的两种方式:
(1)从 Channel 写到 Buffer。
(2)通过 Buffer 的 put()方法写到 Buffer 里。int bytesRead = inChannel.read(buf); //read into buffer buf.put(127);
读写模式转换
flip()
flip 方法将 Buffer 从写模式切换到读模式。调用 flip()方法会将 position 设回 0,并将 limit 设置成之前 position 的值
从 Buffer 中读取数据
有两种方式:
(1)从 Buffer 读取数据到 Channel。
(2)使用 get()方法从 Buffer 中读取数据//read from buffer into channel. int bytesWritten = inChannel.write(buf); byte aByte = buf.get();
1.4、其他方法
rewind()
将 position 设回 0clear()与 compact()都是清空数据,但有所区别:
一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。有两种方式能清空缓冲区:调用 clear()或 compact()方法。clear()方法会清空整个缓冲区。compact()方法只会清除已经读过的数据。任何未读的数据都被移到缓冲区的起始处,新写入的数据将放到缓冲区未读数据的后面
mark()与 reset()一个标记一个回到标记点
通过调用 Buffer.mark()方法,可以标记 Buffer 中的一个特定 position。之后可以通过调用 Buffer.reset()方法恢复到这个 positionbuffer.mark(); //call buffer.get() a couple of times, e.g. during parsing. buffer.reset(); //set position back to mark
1.5、缓冲区
缓冲区可以分为四种类型
分别为缓冲区分片、只读缓冲区、直接缓冲区、内存映射文件 I/O缓冲区分片
根据现有的缓冲区对象来创建一个子缓冲区,即在现有缓冲区上切出一片来作为一个新的缓冲区,但现有的缓冲区与创建的子缓冲区在底层数组层面上是数据共享的,也就是说,子缓冲区相当于是现有缓冲区的一个视图窗口。调用 slice()方法可以创建一个子缓冲区
完整代码:
//缓冲区分片 @Test public void b01() { ByteBuffer buffer = ByteBuffer.allocate(10); for (int i = 0; i < buffer.capacity(); i++) { buffer.put((byte)i); } //创建子缓冲区 buffer.position(3); buffer.limit(7); ByteBuffer slice = buffer.slice(); //改变子缓冲区内容 for (int i = 0; i <slice.capacity() ; i++) { byte b = slice.get(i); b *=10; slice.put(i,b); } buffer.position(0); buffer.limit(buffer.capacity()); while(buffer.remaining()>0) { System.out.println(buffer.get()); } }
只读缓冲区
可以读取它们,但是不能向它们写入数据。可以通过调用缓冲区的 asReadOnlyBuffer()方法
与原缓冲区共享数据,只不过它是只读的。如果原缓冲区的内容发生了变化,只读缓冲区的内容也随之发生变化完整代码
//只读缓冲区 @Test public void b02() { ByteBuffer buffer = ByteBuffer.allocate(10); for (int i = 0; i < buffer.capacity(); i++) { buffer.put((byte)i); } //创建只读缓冲区 ByteBuffer readonly = buffer.asReadOnlyBuffer(); for (int i = 0; i < buffer.capacity(); i++) { byte b = buffer.get(i); b *=10; buffer.put(i,b); } readonly.position(0); readonly.limit(buffer.capacity()); while (readonly.remaining()>0) { System.out.println(readonly.get()); } }
直接缓冲区
加快 I/O 速度
要分配直接缓冲区,需要调用 allocateDirect()方法,而不是 allocate()方法,使用方式与普通缓冲区并无区别下面展示缓冲区的复制代码
完整代码//直接缓冲区 @Test public void b03() throws Exception { String infile = "b://1.txt"; FileInputStream fin = new FileInputStream(infile); FileChannel finChannel = fin.getChannel(); String outfile = "b://2.txt"; FileOutputStream fout = new FileOutputStream(outfile); FileChannel foutChannel = fout.getChannel(); //创建直接缓冲区 ByteBuffer buffer = ByteBuffer.allocateDirect(1024); while (true) { buffer.clear(); int r = finChannel.read(buffer); if(r == -1) { break; } buffer.flip(); foutChannel.write(buffer); } }
内存映射文件 I/O
内存映射文件 I/O 是一种读和写文件数据的方法,它可以比常规的基于流或者基于通道的 I/O 快的多
static private final int start = 0; static private final int size = 1024; //内存映射文件io @Test public void b04() throws Exception { RandomAccessFile raf = new RandomAccessFile("b://1.txt", "rw"); FileChannel fc = raf.getChannel(); MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, start, size); mbb.put(0, (byte) 97); mbb.put(1023, (byte) 122); raf.close(); }
以上是关于java NIO之buffer的主要内容,如果未能解决你的问题,请参考以下文章