对比较大的而不能放入内存的文件进行I/O操作时,如果使用NIO中的内存映射文件对性能效率和速度的提高是非常显著的。首先需要获取文件的通道,然后调用通道的map(FileChannel.MapMode mode,long position,long size)函数将文件从position位置开始的长度为size的内容映射到内存中。具体的效率比较代码示例如下:
- import java.io.BufferedInputStream;
- import java.io.BufferedOutputStream;
- import java.io.DataInputStream;
- import java.io.DataOutputStream;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.RandomAccessFile;
- import java.nio.IntBuffer;
- import java.nio.channels.FileChannel;
- //测试代码是借用thingking in java中的
- public class MappedIO {
- //先声明需要写入的文件的内容的大小
- private static final int NUMOFINT= 4000000 ;
- private static final int NUMOFOUT= 2000000 ;
- //测试类,用来测试使用普通的I/O操作和使用内存文件映射时速度的差别
- abstract static class Tester{
- private String name;
- public Tester(String name){
- this .name=name;
- }
- public void runTest(){
- System.out.println( "使用" +name+ "所消耗的时间:" );
- try {
- //以毫微秒为单位获取测试函数开始前的时间
- long begin=System.nanoTime();
- test();
- //将测试函数结束后的系统的时间减去开始之前的时间获取
- double duration=System.nanoTime()-begin;
- //PrintStream中的使用指定格式字符串和参数将格式化字符串写入此输出流中的方法
- System.out.format( "%.2f\n" , duration/ 1 .0e9);
- } catch (IOException e){
- e.printStackTrace();
- }
- }
- //具体的测试函数中其实不仅有对文件进行读取或写入的时间,还包括消耗的各种初始化I/O对象的时间,而且内存映射文件的初始化对象消耗更要比普通的操作大
- public abstract void test() throws IOException;
- }
- private static Tester[] tests={
- //先使用普通的stream write,并且还是用了Buffered缓冲
- new Tester( "stream write" ){
- public void test() throws IOException{
- DataOutputStream dos= new DataOutputStream( new BufferedOutputStream( new FileOutputStream( "baolei.txt" )));
- for ( int i= 0 ;i<NUMOFINT;i++){
- dos.writeInt(i);
- }
- dos.close();
- }
- },
- //使用内存映射文件方式写入文件时的测试内部类
- new Tester( "mapped write" ){
- public void test() throws IOException{
- //利用RandomAccessFile初始化文件获取通道
- FileChannel fc= new RandomAccessFile( "baolei.txt" , "rw" ).getChannel();
- //利用IntBuffer基本类型视图缓冲器来修改底层的ByteBuffer,实际上ByteBuffer是将数据移进移出通道的唯一方式
- IntBuffer ib=fc.map(FileChannel.MapMode.READ_WRITE, 0 ,fc.size()).asIntBuffer();
- for ( int i= 0 ;i<NUMOFINT;i++){
- ib.put(i);
- }
- fc.close();
- }
- },
- //下面的两个测试方法是测试read文件时的速度,基本和上面的两个一样
- new Tester( "stream read" ){
- public void test() throws IOException{
- DataInputStream dis= new DataInputStream( new BufferedInputStream( new FileInputStream( "baolei.txt" )));
- for ( int i= 0 ;i<NUMOFOUT;i++){
- dis.readInt();
- }
- dis.close();
- }
- },
- new Tester( "mapped read" ){
- public void test() throws IOException{
- FileChannel fc= new RandomAccessFile( "baolei.txt" , "rw" ).getChannel();
- IntBuffer ib=fc.map(FileChannel.MapMode.READ_WRITE, 0 , fc.size()).asIntBuffer();
- while (ib.hasRemaining()){
- ib.get();
- }
- fc.close();
- }
- }
- };
- public static void main(String[] args){
- for (Tester test:tests){
- test.runTest();
- }
- }
- }
可以看到运行后的结果如下:
使用stream write所消耗的时间:
0.92
使用mapped write所消耗的时间:
0.12
使用stream read所消耗的时间:
0.50
使用mapped read所消耗的时间:
0.06
效率确实大幅度提高啊。