包含在包java.nio包中。新IO将文件映射到内存中,因此读写文件速度快了不少。
支持以下特性:
内存映射文件、文件锁定、字符集编码和解码、非阻塞I/O
建立内存映射非常简单:
首先,为文件获取通道(channel)。通过FileInputStream、FileOutputStream、RandomAccessFile中的getChannel方法获取。
FileInputStream in=new FileInputStream(FilePath);
FileChannel channel=in.getChannel();
然后,调用FileChannel的map方法可以获取一个MappedByteBuffer,map的方式有三种:
FileChannel.MapMode.READ_ONLY,缓冲区只读,写入操作引发ReadOnlyBufferException异常。
FileChannel.MapMode.READ_WRITE,缓冲区可读写,这些改变会及时写回文件中。注意,如果其他程序同时映射了相同的文件,它不会立刻察觉到文件变化。多个程序同时对同一文件进行映射,其行为取决于操作系统。有可能无法互斥的操作文件,而导致同步问题,即使你锁定了文件(操作系统可能不支持锁定文件)。
FileChannel.MapMode.PRIVATE,缓冲区可读写,但任何改变只与缓冲区有关,而不会写入文件,这比较适合需要对文件安全写入的情况。
注意,map方法只是一个映射,并不是把所有内容全部读到内存中,所以,即使很大的文件,map方法也会很快返回。
最后,一旦获取了缓冲区,可以使用ByteBuffer类和Buffer超类读写数据。
缓冲区支持顺序和随机访问。
顺序访问全部字节:
while(buffer.hasRemaining())
{
byte b=buffer.get();
...
}
随机访问:
for(int i=0;i
{
byte b=buffer.get(i);
...
}
读取字节数组:
get(byte[] bytes)
get(byte[],int offset,int length)
读取基本类型数值的方法:
getInt
getLong
getShort
getChar
getFloat
getDouble
注意,Java二进制数据使用高字节在前面的顺序,如果需要处理包含低字节在前面的二进制数据文件,可以调用:
buffer.order(ByteOrder.LITTLE_ENDIAN);
要获取缓冲区当前使用的字节顺序,可调用:
ByteOrder b=buffer.order()
将基本类型数据写入缓冲区:
putInt
putLong
putShort
putChar
putFloat
putDouble
以上是一种操作文件的方法,还有一种不用MappedByteBuffer的方法,我们用普通的Buffer来实现对文件的操作:
FileInputStream fin = new FileInputStream("read.txt");
FileChannel fc = fin.getChannel(); // 获取通道
ByteBuffer buffer = ByteBuffer.allocate(1024);// 创建缓冲区
fc.read(buffer);// 将数据从通道读到缓冲区中
System.out.println((char) buffer.get(2));
// System.out.println((char) buffer.get());//直接读 会输出乱码
buffer.flip();// 将limit设置为有效值
FileOutputStream fout = new FileOutputStream("write.txt");
FileChannel fcout = fout.getChannel();
fcout.write(buffer);
关于缓冲区的使用方法:
除了上面的get和put方法外,Buffer有自己独特灵活的读写方法,所以需要知道这些方法的确切用途。
属性:
capacity属性:缓冲区容量
limit属性:当前有效容量(小于或等于limit的位置的数据是有效的)
position属性:当前读写位置
方法:
flip():刷新limit属性(当添加删除元素的时候,limit是不会自动刷新的,所以每次对缓冲区元素个数进行操作的时候,需要调用flip()),重置position为0。
clear():逻辑上清空缓冲区。将position和limit都设置为0。之所以是逻辑上清空,是因为,相应位置上的数据没有被擦写,只是limit成为0了。
hasRemaining():如果还有没读完的数据,返回true(常用于循环遍历读取的时候判断结尾)。
公式:0<=position<=limit<=capacity
以下小例子可以证明这些结论:
import java.nio.*;
public class NewIOBufferExercise1 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
CharBuffer buff=CharBuffer.allocate(8);
System.out.println("capacity:"+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("加入三个元素后,position="+buff.position()+",limit="+buff.limit());
buff.flip();
System.out.println("执行flip方法后,position="+buff.position()+",limit="+buff.limit());
System.out.println("第一个元素:"+buff.get());
System.out.println("取出第一个元素后,position="+buff.position());
buff.clear();
System.out.println("执行clear方法后,position="+buff.position()+",limit="+buff.limit());
System.out.println("执行clear方法后,缓冲区没有被消除,用get取得第三个元素是="+buff.get(2));
System.out.println("执行绝对读取get后,position="+buff.position());
}
}
执行结果是:
capacity:8
limit:8
position:0
加入三个元素后,position=3,limit=8
执行flip方法后,position=0,limit=3
第一个元素:a
取出第一个元素后,position=1
执行clear方法后,position=0,limit=8
执行clear方法后,缓冲区没有被消除,用get取得第二个元素是=c
执行绝对读取get后,position=0