Search code examples
javajava-7deflate

Java 7 Deflating Files


I have a piece of code which uses the deflate algorithm to compress a file:

public static File compressOld(File rawFile) throws IOException
{
    File compressed = new File(rawFile.getCanonicalPath().split("\\.")[0]
            + "_compressed." + rawFile.getName().split("\\.")[1]);

    InputStream inputStream = new FileInputStream(rawFile);
    OutputStream compressedWriter = new DeflaterOutputStream(new FileOutputStream(compressed));
    byte[] buffer = new byte[1000];
    int length;

    while ((length = inputStream.read(buffer)) > 0)
    {
        compressedWriter.write(buffer, 0, length);
    }

    inputStream.close();
    compressedWriter.close();

    return compressed;
}

However, I'm not happy with the OutputStream copying loop since it's the "outdated" way of writing to streams. Instead, I want to use a Java 7 API method such as Files.copy:

public static File compressNew(File rawFile) throws IOException
{
    File compressed = new File(rawFile.getCanonicalPath().split("\\.")[0]
            + "_compressed." + rawFile.getName().split("\\.")[1]);

    OutputStream compressedWriter = new DeflaterOutputStream(new FileOutputStream(compressed));
    Files.copy(compressed.toPath(), compressedWriter);

    compressedWriter.close();

    return compressed;
}

The latter method however does not work correctly, the compressed file is messed up and only a few bytes are copied. How come?


Solution

  • I see mainly two problems.

    1. You copy from the target instead of the source. I think the copying has to be changed to Files.copy(rawFile.toPath(), compressedWriter);.
    2. The Javadoc of copy says: "Note that if the given output stream is Flushable then its flush method may need to invoked after this method completes so as to flush any buffered output." So, you have to call the flush-method of the OutputStream after copy.

    Additionally there is one more point. The Javadoc of copy says:

    It is strongly recommended that the output stream be promptly closed if an I/O error occurs.

    You can close the OutputStream in a finally-block to make sure it happens in case of an error. Another possibility is to use try with resources that was introduced in Java 7.