使用FileChannel管道传输大文件的注意点

今天在项目中有windows系统向solaris系统传输数据的任务。

代码中,使用FileChannel管道传输数据。

  
  
  
  
  1. FileChannel fcin = new FileInputStream(file).getChannel(); 
  2. FileChannel fcout = new FileOutputStream(new File(bakFileDir,file.getName())).getChannel(); 
  3. System.out.println("文件大小:"+fcin.size()); 
  4. long fileSize=fcin.size(); 
  5. fcin.transferTo(0, fcin.size(), fcout); //如查文件小于4g时可不用上边的循环,直接用此即可完成拷贝 
  6. //ByteBuffer bb = ByteBuffer.allocate(1024); 
  7. //while (fcin.read(bb)!=-1){ 
  8. // bb.flip(); 
  9. // fcout.write(bb); 
  10. // bb.clear();//prepare for reading;清空缓冲
  11. //}
  12. fcin.close(); 
  13. fcout.close();

粗看起来代码没什么问题,使用的是【FileChannel.transferTo】方法,我使用了几个小文件进行传输之后,都能够正确复制,没什么问题。但是,当遇到有一个文件特别大(达到了70多MB),这时候报出了如下的错误。

系统资源不足,无法完成请求的服务。】网上调查下来,可能是内存不足的问题。但是我自己这边的机器和对方的机器的内存/虚拟内存,都还是很大的,应该没问题的。

这时候突然想到了以前有发生过JVM内存溢出的异常,这次会不会是同样的问题呢。

这下,不使用直接transferTo方法(虽然网上说,只要传输文件在4G以下,都可以用这种方式),显然是给它忽悠了。所以,改用了如下的这种方式,切块的形式传输。

  
  
  
  
  1. //fcin.transferTo(0, fcin.size(), fcout); //如查文件小于4g时可不用上边的循环,直接用此即可完成拷贝  
  2. ByteBuffer bb = ByteBuffer.allocate(1024);  
  3. while (fcin.read(bb)!=-1){  
  4.     bb.flip();  
  5.     fcout.write(bb);  
  6.     bb.clear();//prepare for reading;清空缓冲 

注释了tranferTo方法,改用了ByteBuffer,果然好了。就是传输速度有点慢,毕竟目前为止是1MB的进行传输。较之前的不管多大的文件都一次性传输的速度要慢一点。

关于设置几MB一次进行文件传输,具体情况具体分析,可以尝试一下再修改其大小。

 

在这里贴出来,就是给大家共享一下,万一碰到相同的问题,可以快速的解决。

你可能感兴趣的:(编程,FileChannel)