java学习笔记:NIO(NEW I/O)
程序员文章站
2024-02-16 10:33:46
...
java学习笔记:NIO(NEW I/O)
(一)为了实现更高效的I/O
(二)是对块进行处理,而不是对一个一个字节处理,这样会更高效。
(三)这里的块就是各种缓冲区,先把数据写到缓冲区中,然后将缓冲区的数据一并写到文件中。
(四)缓冲区类
- ByteBuffer
- ShortBuffer
- CharBuffer
- IntBuffer
- LongBuffer
- FloatBuffer
- DoubleBuffer
(五)以ByteBuffer为例介绍其中的一些方法和属性
- 首先ByteBuffer类提供了一个静态方法来分配缓存的大小,
ByteBuffer b = ByteBuffer.allocate(8);
- ByteBuffer对象中有三个重要的属性,position,limit,capacity,position表示将要把数据插入到哪个位置,随着插入完一个数据后自动加一,limit表示访问缓存中的数据的最大小标,比如limit=8,那么就只能访问到这里,capacity表示缓存大小,limit的初始值和capacity相等。
- put方法将数据放到缓存中,有多种写法。
- get从缓存中得到数据,在使用get的时候,如果传入的下标超过了limit则会报错
java.lang.IndexOutOfBoundsException
- flip方法会将limit=position,然后把position变成0。目的是将缓存中存有数据的部分标明出来,而访问没有数据的部分的时候就会报错
java.lang.IndexOutOfBoundsException
。 - hasRemaining()方法会返回position和limit之间是否有数据
- remaining()会返回position和limit之间有多少个数据,内部实现是limit-position
- 对属性和方法进行检验
//创建一个大小为8的缓存
ByteBuffer b = ByteBuffer.allocate(8);
//输出一下position,limit,capacity属性
System.out.println("position="+b.position());
System.out.println("limit="+b.limit());
System.out.println("capacity="+b.capacity());
//添加数据10,20,30
b.put((byte)10);
b.put((byte)20);
b.put((byte)30);
System.out.println("-----------------");
//再输出一下position,limit,capacity。
//发现position已经变成3了说明,下一个插入的数据要放在3这个位置上
System.out.println("position="+b.position());
System.out.println("limit="+b.limit());
System.out.println("capacity="+b.capacity());
//flip一下
b.flip();
//发现limit变成了3,position变成了0 这个时候说明0到2有数据
System.out.println("-----------------");
System.out.println("position="+b.position());
System.out.println("limit="+b.limit());
System.out.println("capacity="+b.capacity());
//检测是否有数据
if(b.hasRemaining()) {
//得到数据数,然后用for循环遍历数据
for(int i = 0 ;i<b.remaining() ; i++) {
System.out.println(b.get(i));
}
}
(六)通道类Channel,在通道里传输的是块(也就是缓存),用户把数据存到缓存中,然后缓存经过管道存到文件中,或者管道将文件读取到缓存中,用户从缓存中得到字节。
(七)可以通过FileInputStream的getChannel方法返回一个FileChannel对象,从管道读取的时候需要一个缓存,然后再把东西写道管道中。类死于流,但是管道的write方法只会把缓存的positon到limit之间的数据写到管道里,所以在写入管道前调用一下flip方法(如果没有读取满就用flip来调整缓存中的limit),读取完写入到管道中,然后清空一下缓存以便下一次读取。
//如果直接用new FileInputStreamy("D:\\test\\test1.txt").getChannel这种写法
//虽然返回了一个管道但会打开一个流,而这个流有没有名字,也就无法关闭。
//所以分开写
InputStream is = new FileInputStream("D:\\test\\test1.txt");
FileChannel fcIn = ((FileInputStream) is).getChannel();
OutputStream os = new FileOutputStream("D:\\test\\test3.txt");
FileChannel fcOut = ((FileOutputStream) os).getChannel();
ByteBuffer buf = ByteBuffer.allocate(1024);
while(fcIn.read(buf)!=-1) {
buf.flip();
//这里write方法只会读取ByteBuffer对象中position到limit之间的数据
fcOut.write(buf);
//清空一下缓存
buf.clear();
}
is.close();
os.close();
fcIn.close();
fcOut.close();
(八)RandomAccessFile中的内存映射,以输入管道创建一个映射缓存,这个映射缓存
RandomAccessFile read = new RandomAccessFile("D:\\test\\test1", "r");
RandomAccessFile write = new RandomAccessFile("D:\\test\\test3", "rw");
//获得输入输出管道
FileChannel fcIn = read.getChannel();
FileChannel fcOut = write.getChannel();
//得到输入管道的长度
long size = fcIn.size();
//创建输入映射缓存,从0到size即把整个输入管道都映射到缓存中。
//文件中所有的东西都会映射到缓存中。
MappedByteBuffer inBuf = fcIn.map(MapMode.READ_ONLY, 0, size);
//创建输出映射缓存,从0到size
//所有映射缓存中的东西都会映射到文件中
MappedByteBuffer outBuf = fcOut.map(MapMode.READ_ONLY, 0, size);
//然后把输入映射缓存的东西全部写道输出映射缓存中,
for(int i=0;i<size;i++) {
outBuf.put(inBuf.get());
}
read.close();
write.close();
fcIn.close();
fcOut.close();
(九)效率
- 映射
- 管道
- 带缓存的I/O
- 普通I/O