在 JDK 1. 4 中 新 加入 了 NIO( New Input/ Output) 类, 引入了一种基于通道和缓冲区的 I/O 方式,它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆的 DirectByteBuffer 对象作为这块内存的引用进行操作,避免了在 Java 堆和 Native 堆中来回复制数据。
先介绍下NIO的通道(Channel): 在NIO中所有的数据操作都需要通过Channel .相当于对文件插了一个管子,你把数据放进这个通道中,文件里就有了,同样,你文件中的数据,也会存在于管道中.
缓冲区(Buffer): 相当于一个装数据的容器,大小可以由你来指定.这里有几个概念.
容量(capacity):能装多少数据,不能为负,创建后不可改变.
界限(limit): 即limit后的数据无法读取().
位置(position): 标记当前读取数据的位置. 每读取一`个`数据,position+1,当position = limit时,代表当前数据已读完
你创建了一个容量为5的缓冲区.初始的三个重要的概念的位置
---------------------------------------------------------------
@Test
public void fun2() {
ByteBuffer buf = ByteBuffer.allocate(5); //创建一个容量只有5的buffer
System.out.println("capacity :" + buf.capacity()); // capacity() 可以得到buffer的容量大小
System.out.println("limit :" + buf.limit()); // 获取界限所在位置
System.out.println("position :" + buf.position()); // 获取`指针`所在位置
System.out.println("--------------------------");
byte[] bytes1 = "1".getBytes(); // 获取byte数组
byte[] bytes2 = "2".getBytes();
byte[] bytes3 = "3".getBytes();
byte[] bytes4 = "4".getBytes();
byte[] bytes5 = "5".getBytes();
byte[] bytes6 = "6".getBytes();
buf.put(bytes1); //往容器里面放置数据
buf.put(bytes2);
buf.put(bytes3);
buf.put(bytes4);
buf.put(bytes5);
// buf.put(bytes6); //这里会抛出异常 java.nio.BufferOverflowException
System.out.println("position :" + buf.position());
System.out.println("--------------------------");buf.flip(); // 表明我数据准备好了 这里会吧limit的值变成position当前的值(加了5个数据所以是5) ,然后position = 0,锁住capacity-limit的空白区域,放置误读.
System.out.println("capacity :" + buf.capacity());}
---------------------------------------------------------------
复制文件的操作为 从InputStream.getChannel()来获取通道,然后流入缓冲区中,后再写入OutputStream的通道中.
代码如下:
----------------------------------------------------------------------------------------
@Test
public void fun3() throws IOException {
MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
// MappendByteBuffer 也是byteBuffer的一个子类 (直接字节缓冲区,其内容是文件的内存映射区域。)
这里面保存了当前通道中的所有数据. map()方法需要三个参数,第一个是读写权限,第二个是从哪里开始读,第三个是读多少到缓冲区中.
}
// 下面演示分批次读取
// 分批次读写
@Test
public void fun4() throws IOException {
RandomAccessFile inFile = new RandomAccessFile("E:\\practice\\nio\\source\\a.txt","rw");
RandomAccessFile outFile = new RandomAccessFile("E:\\practice\\nio\\target\\a.txt","rw");
// 获取输入流的通道
FileChannel inChannel = inFile.getChannel();
// 获取输出流的通道
FileChannel outChannel = outFile.getChannel();
// 构建缓冲区
ByteBuffer buffer = ByteBuffer.allocate(256);
// 放置数据
while(inChannel.read(buffer) != -1){
// 准备好了开始复制 limit跑到原来position的位置,position归0 目的是锁住buffer 的空白区 防止读到null
buffer.flip();
// 写入通道
outChannel.write(buffer); // 写入通道后数据不见了 所以后续的输出为空 ,但是要是把写数据放在打印后面可能会抛出异常
// 为了打印设置的字符集
Charset charset = Charset.forName("GBK");
// 打印流中的数据
CharsetDecoder decoder = charset.newDecoder();
// 可能会抛出 MalformedInputExeption 原因是 `半个中文问题 `
CharBuffer decode = decoder.decode(buffer);
System.out.println(decode);
System.out.println("------------------------");
// position 置于0 limit = capacity 重置buffer 为下一次做准备
buffer.compact();
}
}