《Java程序性能优化》3.3 使用NIO提升性能(未完)
p:102-118
流与NIO的不同
流以字节为单位,NIO基于块(block)为单位。
channel是双向的通道。stream是单向的。
NIO组件
NIO两个重要组件:通道channel和缓冲buffer
通道表示缓冲数据的源头或者目的地。
缓冲是一块连续的内存, 是NIO读写数据的中转地。
通道(Channel)
不能直接对channel进行读写操作,必须通过Buffer来进行。
如: 在读一个Channel的时候,需要先将数据读入到相对应的Buffer,然后在Buffer中进行读取。
fc=fileInputStream.getChannel()
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);//buffer初始化的时候,pos=0,limit=capacity
fc.read(byteBuffer)
fc.close();
byeBuffer.flip();//limit=pos;pos=0; 表示只能读pos--limit的内容
特别注意:
FileChannel outChannel = fileOutputStream.getChannel();
FileChannel inChannel = fileinputStream.getChannel();
inChannel.read(buff) 是 读取通道的内容到buffer中
outChannel.write(b)是将buffer中的内容(limit到pos位置)写到通道对应的位置
缓冲(Buffer)
Buffer基本参数
参数 | 说明 |
---|---|
位置(position) | 当前操作的位置,0<=position<=limit<=capacity |
容量(capacity) | 操作位置的最大值 |
上限(limit) | 读/写操作的范围 ,0<=limit<=capacity |
对Buffer的操作:clear、flip、rewind
注意:实际没操作数据,只是操作了limit,pos。三者都会清除mark。
**clear:**清除此缓冲区。将位置设置为 0,将限制设置为容量(limit=capacity),并丢弃标记(mark)。 :它将限制设置为容量大小,将位置设置为 0。 ps:变成初始状态,pos=0,limit=capcity=max
**flip:**使缓冲区为一系列新的通道写入或相对获取 操作做好准备。:反转此缓冲区。首先将限制设置为当前位置,然后将位置设置为 0。如果已定义了标记,则丢弃该标记。 。 ps:规定写入读取的最大limit,limit=position,position=0;
rewind: 使缓冲区为重新读取已包含的数据做好准备:它使限制保持不变,将位置设置为 0,并丢弃标记。 ps:position=0;丢弃掉上次pos修改。 所以可以重复读取
mark与reset
像书签一样, 方便快速恢复到标记的位置(position)。
mark:在此缓冲区的位置设置标记。
reset:改变position为之前标记的值
public final Buffer reset()将此缓冲区的位置重置为以前标记的位置。
调用此方法不更改也不丢弃标记的值。
返回:
此缓冲区
抛出:
InvalidMarkException - 如果尚未设置标记
待续。。
测试用例
package com.gkwind.nio;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
/**
* @Author thewindkee
* @Date 2019/4/18 0018 下午 12:19
*/
public class NIOTest {
public static void main(String[] args) throws IOException {
testFlipAndRewind();
testChannel();
testMarkAndReset();
}
private static ByteBuffer prepareBuffer() {
System.out.println("prepareBuffer");
ByteBuffer b = ByteBuffer.allocate(15);//初始化,pos=0,limit=capacity
System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=15 capacity=15 position=0
for (int i = (int)'a'; i <(int)'a'+ 10; i++) {
b.put((byte) i);
}
return b;
}
private static void testChannel() throws IOException {
ByteBuffer b = prepareBuffer();
b.get();
// channel
//limit=1
File file = new File("a.txt");
System.out.println(file.getAbsolutePath());
FileOutputStream fileOutputStream = new FileOutputStream(file);
FileChannel outChannel = fileOutputStream.getChannel();
outChannel.write(b);
// fileOutputStream.flush();
outChannel.close();
//文件中 包含 bcdefghij
System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=10 capacity=15 position=10
File bfile = new File("b.txt");
FileUtils.write(bfile, "中国", "UTF-8");//准备数据
FileInputStream fileInputStream = new FileInputStream(bfile);
FileChannel inChannel = fileInputStream.getChannel();
//清空buffer
b.clear();//pos=0,limit=capacity
System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=15 capacity=15 position=0
inChannel.read(b);
System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=15 capacity=15 position=6
b.flip();//确定limit位置,准备读
System.out.println(new String(b.array(),b.position(),b.limit()));//中国
}
private static void testFlipAndRewind() {
System.out.println("testFlipAndRewind");
//rewind and flip
ByteBuffer b = prepareBuffer();
// b.put("中国".getBytes("GBK"));
System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=15 capacity=15 position=10
b.flip();//limit=pos,pos=0;定义能get/put的最大位置
System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=10 capacity=15 position=0
System.out.println("get...");
// byte[] dst = new byte[1024];
// b.get(dst,b.position(),b.limit());//会引起变化
// System.out.println(dst.length+" "+new String(dst));//abcdefghij 注意包含了空格(1024-10个)
byte [] des2 = new byte[b.limit()];
b.get(des2);//会引起变化
System.out.println(new String(des2));//abcdefghij
System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=10 capacity=15 position=10
System.out.println("rewind..");
b.rewind();//丢弃掉pos变化,pos=0; limit不变;方便重新读取
System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=10 capacity=15 position=0
System.out.println(new String(b.array(), b.position(), b.limit()));//不会改变limit
System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=10 capacity=15 position=0
System.out.println(b.get());//limit++
System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=10 capacity=15 position=1
}
private static void testMarkAndReset() {
System.out.println("testMarkAndReset");
//mark and reset
ByteBuffer b = prepareBuffer();
b.clear();
for (int i = (int)'a'; i <(int)'a'+ 10; i++) {
b.put((byte) i);
}
System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=15 capacity=15 position=6
b.flip();
System.out.println("flip... 准备读...");
b.get();
System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=15 capacity=15 position=6
b.mark();
System.out.println("mark...");
b.get();
System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=15 capacity=15 position=6
// b.clear();//clear会清除mark的位置
b.reset();
System.out.println("reset...");
System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=15 capacity=15 position=6
b.limit(3);//会清除mark的位置
System.out.println("limit(3)...");
System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=15 capacity=15 position=6
}
}