0

I am completely new to java, I have decided to learn it by doing a small project in it. I need to compress some string using zlib and write it to a file. However, file turn out to be too big in size. Here is code example:

String input = "yasar\0yasar"; // test input. Input will have null character in it.
byte[] compressed = new byte[100];  // hold compressed content

Deflater compresser = new Deflater();
compresser.setInput(input.getBytes());
compresser.finish();
compresser.deflate(compressed);
File test_file = new File(System.getProperty("user.dir"), "test_file");
try {
    if (!test_file.exists()) {
        test_file.createNewFile();
    }
    try (FileOutputStream fos = new FileOutputStream(test_file)) {
        fos.write(compressed);
    }
} catch (IOException e) {
    e.printStackTrace();
}

This write a 1 kilobytes file, while the file should be at most 11 bytes (because the content is 11 bytes here.). I think problem is in the way I initialize the byte array compressed as 100 bytes, but I don't know how big the compreesed data will be in advance. What am I doing wrong here? How can I fix it?

yasar
  • 13,158
  • 28
  • 95
  • 160
  • use the `resultLength` as the [documentation](http://docs.oracle.com/javase/7/docs/api/java/util/zip/Deflater.html) does. – zapl Aug 07 '13 at 10:13
  • @zapl That gives the length of compressed data after the compression is done. I need to initialize the output array before the initialization, otherwise I get an error: `variable compressed might not have been initialized` – yasar Aug 07 '13 at 10:17
  • @HighPerformanceMark I am not sure how to check. I am on windows 7 (64 bit) – yasar Aug 07 '13 at 10:19

2 Answers2

1

If you don't want to write the whole array and instead write just the part of it that was filled by Deflater use OutputStream#write(byte[] array, int offset, int lenght)

Roughly like

String input = "yasar\0yasar"; // test input. Input will have null character in it.
byte[] compressed = new byte[100];  // hold compressed content

Deflater compresser = new Deflater();
compresser.setInput(input.getBytes());
compresser.finish();
int length = compresser.deflate(compressed);
File test_file = new File(System.getProperty("user.dir"), "test_file");
try {
    if (!test_file.exists()) {
        test_file.createNewFile();
    }
    try (FileOutputStream fos = new FileOutputStream(test_file)) {
        fos.write(compressed, 0, length); // starting at 0th byte - lenght(-1)
    }
} catch (IOException e) {
    e.printStackTrace();
}

You will probably still see 1kB or so in Windows because what you see there seems to be either rounded (you wrote 100 bytes before) or it refers to the size on the filesystem which is at least 1 block large (should be 4kb IIRC). Rightclick the file and check the size in the properties, that should show the actual size.


If you don't know the size in advance, don't use Deflater, use a DeflaterOutputStream that writes data of any length compressed.

try (OutputStream out = new DeflaterOutputStream(new FileOutputStream(test_file))) {
    out.write("hello!".getBytes());
}

Above example will use the default values for deflating but you can pass a configured Deflater in the constructor of DeflaterOutputStream to change the behavior.

Community
  • 1
  • 1
zapl
  • 63,179
  • 10
  • 123
  • 154
  • Accept for the first part, +1 for the output stream ;) – yasar Aug 07 '13 at 10:32
  • Streams are usually much easier to use and you can plug them together, e.g. write data that is first encrypted, then compressed, then maybe something else like BASE64 encoded just by wrapping streams in streams. – zapl Aug 07 '13 at 10:36
0

you write to file all 100 bytes of compressed array, but you have to write only really compressed bytes returned by deflater. int compressedsize = compresser.deflate(compressed);
fos.write(compressed, 0, compressedsize);

Luca Basso Ricci
  • 17,829
  • 2
  • 47
  • 69