您的位置:首页 > 编程语言 > Java开发

JAVA NIO文件映射、通道、流读写文件示例

2014-02-09 16:25 489 查看
本例使用FileChannel和 BufferedInputStream等测试对比。

TestHandler.java 用于实现动态代理,测试运行效率

package com.test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class TestHandler implements InvocationHandler{

private Object obj=null;

public TestHandler(Object obj){
this.obj=obj;
}

public static Object newInstance(Object obj){
Object result=Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(), new TestHandler(obj));
return result;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result=null;
System.out.println("执行中...");

long start=System.currentTimeMillis();
result=method.invoke(obj, args);

long end=System.currentTimeMillis();
System.out.println("执行完成,耗时:"+(end-start));

return result;
}

}


INIOTest.java

package com.test;

import java.io.IOException;

public interface INIOTest{
public void copyFileMapped(String oldPath,String newPath)  throws IOException;
public void copyFileNIO(String oldPath,String newPath)  throws IOException;
public void copyFile(String oldPath,String newPath)  throws IOException;
}


Test.java

package com.test;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class Test implements INIOTest{
public void copyFileMapped(String oldPath,String newPath)  throws IOException{
long length=0;
RandomAccessFile raf=new RandomAccessFile(oldPath , "r");
FileChannel fcr=raf.getChannel();
length=fcr.size();
//返回要读取文件的映射内存区块
MappedByteBuffer mbb=fcr.map(FileChannel.MapMode.READ_ONLY, 0, length);
ByteBuffer buffer=mbb.get(new byte[(int)length]);

//要写入的文件
RandomAccessFile raw=new RandomAccessFile(newPath, "rw");
FileChannel fcw=raw.getChannel();
MappedByteBuffer mbbw=fcw.map(FileChannel.MapMode.READ_WRITE, 0, length);
for(int i=0;i<length;i++){
mbbw.put(i,buffer.get(i));
}
fcw.close();
fcr.close();
raf.close();
raw.close();
/**
* MappedByteBuffer是java平台共享内存的实现,把硬盘虚拟为内存,
* 主要用于进程间共享数据,所以在进程没有退出前文件是不允许删除的。
* 一个映射的字节缓冲区和文件映射,它代表仍然有效,直到缓冲本身是垃圾收集。
*/
raf=null;
raw=null;
System.gc();
try {
//等待垃圾回收
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}

}
public void copyFileNIO(String oldPath,String newPath) throws IOException{
FileInputStream fis=new FileInputStream(oldPath);
FileOutputStream fos=new FileOutputStream(newPath);
//获取输入输出通道
FileChannel fcin=fis.getChannel();
FileChannel fout=fos.getChannel();
//创建缓冲区
ByteBuffer buffer=ByteBuffer.allocate(1024);
while(true){
//clear方法重设缓冲区,使它可以接受读入的数据
buffer.clear();
int len=fcin.read(buffer);
if(len==-1){

break;
}
//写模式转换成读模式。该限制设置为当前的位置然后位置设置为零。如果标记定义然后丢弃。
//flip方法让缓冲区可以将新读入的数据写入另一个通道
buffer.flip();
fout.write(buffer);
}
fcin.close();
fout.close();
}

public void copyFile(String oldPath,String newPath) throws IOException{
FileInputStream fis=new FileInputStream(oldPath);
FileOutputStream fos=new FileOutputStream(newPath);

BufferedInputStream bis=new BufferedInputStream(fis);
BufferedOutputStream bos=new BufferedOutputStream(fos);
byte[] buffer=new byte[1024];

int len=0;
while((len=bis.read(buffer))!=-1){
bos.write(buffer,0,buffer.length);
}
bis.close();
bos.close();
}
public static void main(String agrs[]){

INIOTest test1=(INIOTest)TestHandler.newInstance(new Test());
try {
test1.copyFileMapped("D:\\upan\\VC++6.0简体中文版.rar","D:\\VC++6.0简体中文版.rar");
test1.copyFileNIO("D:\\upan\\VC++6.0简体中文版.rar","D:\\VC++6.0简体中文版.rar");
test1.copyFile("D:\\upan\\VC++6.0简体中文版.rar","D:\\VC++6.0简体中文版.rar");
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}

}

}




第一个为使用文件映射读写耗时

第二个为文件通道(Channel)读写文件耗时

第三个位BufferedInputStream等耗时

测试多次均是Channel,文件映射读写耗时较稳定,时间也比较短,BufferedInputStream时间也不错,和映射差不多(个人测试的是180M的文件,大文件建议还是使用文件映射可能好点)

特别需要注意的是文件映射无法关闭,MappedByteBuffer是java平台共享内存的实现,把硬盘虚拟为内存,主要用于进程间共享数据,所以在进程没有退出前文件是不允许删除的。也无法访问它。所以这里将它置为null,并等待垃圾回收它。

参考:http://yipsilon.iteye.com/blog/298153
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: