mcacorner
mcacorner

Reputation: 1274

java : corrupted zip file created when copy using nio

I have implement following code to copy file(binary file) code

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);
            }
        }

    }

I have test code with one zip file. when i verify file I found that file which generated is corrupt(size was increased). Source zip file is about 9GB.

Upvotes: 0

Views: 803

Answers (3)

Alen Vrečko
Alen Vrečko

Reputation: 886

Unless you have a good reason best to use Files.copy(Path, Path, CopyOption...).

Upvotes: 0

mavarazy
mavarazy

Reputation: 7735

Try this:

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

Also, I would refer to IOUtils implementation, as a reference

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

specifically

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

Upvotes: 2

G_H
G_H

Reputation: 11999

The transferTo method's first argument gives the position from which to transfer, not relative to where the stream left off, but relative to the start of the file. Since you put 0 there it will always transfer from the start of the file. So that line needs to be

bytesTransferred += inChannel.transferTo(bytesTransferred , inChannel.size(), outChannel);

mavarazy mentioned in his answer he's not sure if you need a loop when using inChannel.size(), since the expectation is that if you supply the whole size it will copy the entire file. However, the actual transfer might be less than the requested number of bytes if the output channel's buffer has less room available. So you do need the loop as in his second code snippet.

Upvotes: 1

Related Questions