今天在项目中有windows系统向solaris系统传输数据的任务。
代码中,使用FileChannel管道传输数据。
- FileChannel fcin = new FileInputStream(file).getChannel();
- FileChannel fcout = new FileOutputStream(new File(bakFileDir,file.getName())).getChannel();
- System.out.println("文件大小:"+fcin.size());
- long fileSize=fcin.size();
- fcin.transferTo(0, fcin.size(), fcout); //如查文件小于4g时可不用上边的循环,直接用此即可完成拷贝
- //ByteBuffer bb = ByteBuffer.allocate(1024);
- //while (fcin.read(bb)!=-1){
- // bb.flip();
- // fcout.write(bb);
- // bb.clear();//prepare for reading;清空缓冲
- //}
- fcin.close();
- fcout.close();
粗看起来代码没什么问题,使用的是【FileChannel.transferTo】方法,我使用了几个小文件进行传输之后,都能够正确复制,没什么问题。但是,当遇到有一个文件特别大(达到了70多MB),这时候报出了如下的错误。
【系统资源不足,无法完成请求的服务。】网上调查下来,可能是内存不足的问题。但是我自己这边的机器和对方的机器的内存/虚拟内存,都还是很大的,应该没问题的。
这时候突然想到了以前有发生过JVM内存溢出的异常,这次会不会是同样的问题呢。
这下,不使用直接transferTo方法(虽然网上说,只要传输文件在4G以下,都可以用这种方式),显然是给它忽悠了。所以,改用了如下的这种方式,切块的形式传输。
- //fcin.transferTo(0, fcin.size(), fcout); //如查文件小于4g时可不用上边的循环,直接用此即可完成拷贝
- ByteBuffer bb = ByteBuffer.allocate(1024);
- while (fcin.read(bb)!=-1){
- bb.flip();
- fcout.write(bb);
- bb.clear();//prepare for reading;清空缓冲
- }
注释了tranferTo方法,改用了ByteBuffer,果然好了。就是传输速度有点慢,毕竟目前为止是1MB的进行传输。较之前的不管多大的文件都一次性传输的速度要慢一点。
关于设置几MB一次进行文件传输,具体情况具体分析,可以尝试一下再修改其大小。
在这里贴出来,就是给大家共享一下,万一碰到相同的问题,可以快速的解决。