JAVA NIO 学习笔记一

在 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时,代表当前数据已读完 

JAVA NIO 学习笔记一_第1张图片

你创建了一个容量为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()); 
System.out.println("limit :" + buf.limit());  //此时limit = 5
System.out.println("position :" + buf.position());//此时position= 0
System.out.println("--------------------------");
byte b = buf.get();  // 拿到第一个元素 
System.out.println(b);   // 输出为 49  1对应的ascii表值为49 
System.out.println("capacity :" + buf.capacity());  
System.out.println("limit :" + buf.limit());
System.out.println("position :" + buf.position());  //position = 1
System.out.println("--------------------------");
buf.clear();// 这个操作把 position设置为0    把limit设置为capacity  .
System.out.println("capacity :" + buf.capacity());   // 
System.out.println("limit :" + buf.limit());
System.out.println("position :" + buf.position());  // position = 0
System.out.println("--------------------------");
byte b2 = buf.get(2);   //但是你会发现 还能拿到值,说明缓冲区没有被清空
System.out.println(b2);  // 输出51 
System.out.println("capacity :" + buf.capacity());
System.out.println("limit :" + buf.limit());
System.out.println("position :" + buf.position());   // position = 0

}

---------------------------------------------------------------

复制文件的操作为 从InputStream.getChannel()来获取通道,然后流入缓冲区中,后再写入OutputStream的通道中.

代码如下:

----------------------------------------------------------------------------------------

                @Test

                public void fun3() 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 channel = inFile.getChannel();
// 把通道里的  数据 全都放到  缓冲区中

MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());

                // MappendByteBuffer 也是byteBuffer的一个子类      (直接字节缓冲区,其内容是文件的内存映射区域。)

这里面保存了当前通道中的所有数据.   map()方法需要三个参数,第一个是读写权限,第二个是从哪里开始读,第三个是读多少到缓冲区中.


// 为了打印设置的字符集
Charset charset = Charset.forName("GBK");

// 输出流获取通道 从buffer中写入
outFile.getChannel().write(map);
map.compact();

// 打印流中的数据
CharsetDecoder decoder = charset.newDecoder();
CharBuffer charBuffer = decoder.decode(map);
System.out.println(charBuffer);

}

// 下面演示分批次读取   

// 分批次读写
@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();
}

}


你可能感兴趣的:(java,java,nio)