2013-08-07 3 views
0

Я совершенно не знаком с java, я решил изучить его, выполнив небольшой проект. Мне нужно сжать некоторую строку с помощью zlib и записать ее в файл. Однако файл оказывается слишком большим по размеру. Вот пример кода:Сжатие Zlib слишком велико в размере

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

Это запись файла в 1 килобайт, в то время как файл должен быть не более 11 байт (потому что содержание 11 байт здесь.). Я думаю, что проблема в том, что я инициализирую массив байтов, сжатый как 100 байт, но я не знаю, насколько велики будут данные, предоставленные вместе. Что я здесь делаю неправильно? Как я могу это исправить?

+0

использовать 'resultLength' как [документации] (http://docs.oracle.com/javase/7/docs/api/java/util/zip/Deflater.html) делает. – zapl

+0

@zapl Это дает длину сжатых данных после завершения сжатия. Мне нужно инициализировать выходной массив до инициализации, иначе я получаю сообщение об ошибке: 'переменная сжата, возможно, не была инициализирована' – yasar

+0

@HighPerformanceMark Я не уверен, как проверить. Я нахожусь на окнах 7 (64 бит) – yasar

ответ

1

Если вы не хотите, чтобы написать весь массив, а вместо того, чтобы писать только ту ее часть, которая была заполнена на Deflater использования OutputStream#write(byte[] array, int offset, int lenght)

Примерно как

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

Вы, вероятно, по-прежнему видеть 1kB или поэтому в Windows, потому что то, что вы видите там, похоже, либо округлено (вы написали 100 байт раньше), либо оно относится к размеру файловой системы, который не менее 1 block большой (должен быть 4kb IIRC). Щелкните правой кнопкой мыши файл и проверьте размер в свойствах, который должен показывать фактический размер.


Если вы не знаете размер заранее, не используйте Deflater, используйте DeflaterOutputStream, который записывает данные любой длины сжатой.

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

Приведенный выше пример будет использовать значения по умолчанию для сдувания, но вы можете передать настроенный Deflater в конструкторе DeflaterOutputStream изменить поведение.

+0

Примите для первой части +1 для выходного потока;) – yasar

+0

Потоки обычно намного проще в использовании, и вы можете их подключить, например. записывать данные, которые сначала зашифрованы, а затем сжаты, а затем, возможно, что-то другое, например BASE64, закодированное только путем обтекания потоков в потоках. – zapl

0

вы записываете в файл все 100 байтов массива compressed, но вам нужно написать только действительно сжатые байты, возвращаемые deflater. int compressedsize = compresser.deflate(compressed);
fos.write(compressed, 0, compressedsize);