从JDK1.4开始,Java 提供了一系列改进的输入和输出处理的新功能,这些功能被称为新IO,新增了许多用于处理输入,输出的类,这些类都被放在java.nio的包以及子包下,并且对原java.io包中的很多类都以NIO的方式,进行了改写,新增了满足NIO的功能。
新IO和传统的IO有相同的目的,都是用于进行输入和输出的,但新IO使用了不同的方式来处理输入输出,新IO采取的方式是采用内存映射的方式来处理输入输出,新IO将文件或文件中的一段区域映射到内存中,这样就可以像访问内存一样来访问文件了,这种方式类似虚拟内存的概念,通过这种方式来进行输入输出比传统的输入输出要快的多。
Channel(通道)和Buffer(缓冲)是新IO中的两个核心对象,Channel是对传统的输入输出系统的模拟,在新IO系统中所有的数据都要通过通道传输,他们之间的最大区别就是它提供了一个map方法,可以通过该map方法将一块数据映射到内存中,传统的IO是面向流的处理,而新的IO则是面向块的处理。
Buff可以被理解成一个容器,它的本质是一个数组,发送到Channel的所有对象都必须放在Buffer中,而从Channel中,读取的数据也必须先放到Buffer中,除了Channel和Buffer之外,新IO还提供了用于将Unicode字符串映射成字节序列以及逆映射的操作的Charset类,也提供了支持支持非阻塞式的Selector类。
Buffer类的几个方法如下:
方法名 |
描述 |
capacity() |
返回的buffer的容量大小 |
hasRemaining() |
当前位置position和limit之间是否还有元素可供处理 |
limit() |
返回界限值 |
mark() |
在0和position之间做位置标记 |
position() |
buffer中的position值 |
remaining() |
返回当前位置和界限之间的元素个数 |
reset() |
将位置转到mark所在的位置 |
rewind() |
将位置设置0,取消mark标记 |
put() |
支持批量的数据写入 |
get() |
支持数据读取 |
注意,使用put或get访问Buffer中的数据时,分为绝对和相对来种情况:
相对:从Buffer的当前position处开始读取或写入数据,然后将位置的值按处理元素的个数增加
绝对: 直接根据索引向Buffer中读取或写入数据,使用绝对方式访问Buffer里的数据时,并不会影响位置的值。
下面散仙给出测试的例子:
package com.qin.sanxian.newio;
import java.nio.CharBuffer;
/**
* @author 三劫散仙
* 测试Java 新IO的buffer
*
* */
public class TestBuffer {
public static void main(String[] args)throws Exception {
//创建一个Buffer对象,allcote分配的容量为8
CharBuffer buff=CharBuffer.allocate(8);
System.out.println("容量:"+buff.capacity());
System.out.println("限制大小,limit: "+buff.limit());
System.out.println("位置: position: "+buff.position());
//放入三个元素
buff.put("a");
buff.put("b");
buff.put("c");
System.out.println("加入三个元素后位置 : "+buff.position());
//此方法是会将limit设置为position的位置,将position的位置为0
buff.flip();
System.out.println("执行filp后,limit的位置:"+buff.limit());
System.out.println("执行filp后,position的位置:"+buff.position());
//取出,第一个元素后
System.out.println(buff.get(0));
System.out.println("position: "+buff.position());
//调用clear方法后 ,将position置为0,limit置为capacity
buff.clear();
System.out.println("执行clean后,limit ="+buff.limit());
System.out.println("执行clean后,position = "+buff.position());
System.out.println("执行clear后,缓冲区的内容没有被清除: "+buff.get(0));
System.out.println("执行绝对读取后,position= "+buff.position());
}
}
输出结果如下:
容量:8
限制大小,limit: 8
位置: position: 0
加入三个元素后位置 : 3
执行filp后,limit的位置:3
执行filp后,position的位置:0
a
position: 0
执行clean后,limit =8
执行clean后,position = 0
执行clear后,缓冲区的内容没有被清除: a
执行绝对读取后,position= 0
Channel与Buffer的简单测试:
package com.qin.sanxian.newio;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
/**
*
* Channel测试
* **/
public class TestChannel {
public static void main(String[] args) throws Exception{
//read();
// write();
moreRead();
}
/**
*
* 读取一个文件的数据
* 写入到另一个文件里
* **/
public static void read()throws Exception{
File f=new File("F:\\1\\text.txt");
//创建流获取channel对象
FileChannel inChannel=new FileInputStream(f).getChannel();
FileChannel outChannel=new FileOutputStream("abc.txt").getChannel();
//将FileChannel里的数据全部映射成ByteBuffer;
MappedByteBuffer buffer=inChannel.map(FileChannel.MapMode.READ_ONLY, 0, f.length());
//将f的数据全部输出
outChannel.write(buffer);
buffer.clear();//复原位置
Charset c=Charset.forName("UTF-8");
CharsetDecoder decoder=c.newDecoder();//创建解码器
//解码buffer
CharBuffer charBuffer=decoder.decode(buffer);
System.out.println(charBuffer);
outChannel.close();//关闭流
inChannel.close();//关闭流
}
/**
*
* 写入测试
* */
public static void write()throws Exception{
File f=new File("F:\\1\\text.txt");
//获取一个RandomAccessFile对象
RandomAccessFile raf=new RandomAccessFile(f, "rw");
//获取FileChannel
FileChannel channel=raf.getChannel();
//将文件全部映射到内存中
ByteBuffer buffer=channel.map(FileChannel.MapMode.READ_WRITE, 0, f.length());
//控制原来的的指针到最后一步
channel.position(f.length());
channel.write(buffer);//拷贝已有数据
channel.close();//释放资源
raf.close();//关闭流
}
/**
* 多次读取数据
*
* **/
public static void moreRead()throws Exception{
FileInputStream f=new FileInputStream(new File("F:\\1\\text.txt"));
//创建一个fileChannel
FileChannel channel=f.getChannel();
//定义一个ByteBuffer对象
ByteBuffer buff=ByteBuffer.allocate(103);
//将FileChannel的数据放入ByteBuffer中
while(channel.read(buff)!=-1){
buff.flip();//封印未读取的空间
//创建Charset对象
Charset charset=Charset.forName("UTF-8");
//创建解码器对象
CharsetDecoder decoder=charset.newDecoder();
//将字节内容转码
CharBuffer cbuff=decoder.decode(buff);
System.out.println(cbuff);
//为下一次,读取数据做准备,注意其并不会清空缓存内容
buff.clear();
}
channel.close();
f.close();
}
}