java:使用nio进行复制时创建的损坏的zip文件

时间:2017-05-19 10:58:09

标签: java io nio

我已经实现了以下代码来复制文件(二进制文件) 代码

private void copyFileWithChannels(File aSourceFile, File aTargetFile) {
        log("Copying files with channels.");        
        FileChannel inChannel = null;
        FileChannel outChannel = null;
        FileInputStream inStream = null;
        FileOutputStream outStream = null;      
        try {
            inStream = new FileInputStream(aSourceFile);
            inChannel = inStream.getChannel();
            outStream = new  FileOutputStream(aTargetFile);        
            outChannel = outStream.getChannel();
            long bytesTransferred = 0;
            while(bytesTransferred < inChannel.size()){
                bytesTransferred += inChannel.transferTo(0, inChannel.size(), outChannel);
            }
        }
        catch(FileNotFoundException e){
            log.error("FileNotFoundException in copyFileWithChannels()",e);
        }
        catch (IOException e) {
            log.error("IOException in copyFileWithChannels()",e);           
        }
        catch (Exception e) {
            log.error("Exception in copyFileWithChannels()",e);
        }
        finally {
            try{
                if (inChannel != null) inChannel.close();
                if (outChannel != null) outChannel.close();
                if (inStream != null) inStream.close();
                if (outStream != null) outStream.close();
            }catch(Exception e){
                log.error("Exception in copyFileWithChannels() while closing the stream",e);
            }
        }

    }

我有一个zip文件的测试代码。当我验证文件时,我发现生成的文件已损坏(大小增加)。 源zip文件大约是9GB。

3 个答案:

答案 0 :(得分:2)

试试这个:

  while(bytesTransferred < inChannel.size()){
      bytesTransferred += inChannel.transferTo(bytesTransferred, inChannel.size() - bytesTransferred, outChannel);
  }

另外,我将引用IOUtils实现作为参考

https://github.com/apache/commons-io/blob/master/src/main/java/org/apache/commons/io/FileUtils.java

具体地

private static void doCopyFile(final File srcFile, final File destFile, final boolean preserveFileDate)

答案 1 :(得分:1)

transferTo方法的第一个参数给出了传输的位置,而不是相对于流停止的位置,而是相对于文件的开头。由于您将0放在那里,它将始终从文件的开头传输。所以这条线需要

bytesTransferred += inChannel.transferTo(bytesTransferred , inChannel.size(), outChannel);
mavarazy在他的回答中提到他不确定在使用inChannel.size()时是否需要循环,因为期望是如果你提供整个大小,它将复制整个文件。但是,如果输出通道的缓冲区具有较少的可用空间,则实际传输可能小于请求的字节数。所以你需要在他的第二个代码片段中使用循环。

答案 2 :(得分:0)

除非您有充分的理由使用Files.copy(Path, Path, CopyOption...)