Java: как сжать byte [] с помощью ZipOutputStream без промежуточного файла - PullRequest
0 голосов
/ 05 октября 2019

Требование: сжать байт [], чтобы получить другой байт [], используя java.util.zip.ZipOutputStream, НО без использования каких-либо файлов на диске или в памяти (как здесь https://stackoverflow.com/a/18406927/9132186). Возможно ли это вообще?

Все примеры, которые я нашел в сети, читают из файла (.txt) и записывают в файл (.zip). ZipOutputStream для работы нужен ZipEntry, а ZipEntry нужен файл.

Однакомой пример использования следующий: мне нужно сжимать фрагмент (скажем, 10 МБ) файла за раз, используя формат zip, и добавлять все эти сжатые фрагменты, чтобы создать файл .zip. Но когда я разархивирую файл .zipзатем он поврежден.

Я использую файлы в памяти, как предложено в https://stackoverflow.com/a/18406927/9132186, чтобы избежать файлов на диске, но мне нужно решение и без этих файлов.

  public void testZipBytes() {
    String infile = "test.txt";
    FileInputStream in = new FileInputStream(infile);

    String outfile = "test.txt.zip";
    FileOutputStream out = new FileOutputStream(outfile);

    byte[] buf = new byte[10];
    int len;
    while ((len = in.read(buf)) > 0) {
      out.write(zipBytes(buf));
    }
    in.close();
    out.close();
  }

  // ACTUAL function that compresses byte[]

  public static class MemoryFile {
    public String fileName;
    public byte[] contents;
  }

  public byte[] zipBytesMemoryFileWORKS(byte[] input) {
    MemoryFile memoryFile = new MemoryFile();
    memoryFile.fileName = "try.txt";
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ZipOutputStream zos = new ZipOutputStream(baos);
    ZipEntry entry = new ZipEntry(memoryFile.fileName);
    entry.setSize(input.length); 
    zos.putNextEntry(entry); 
    zos.write(input);
    zos.finish();
    zos.closeEntry();
    zos.close();
    return baos.toByteArray();
  }

Сценарий 1: если test.txt содержит небольшой объем данных (менее 10 байт), например «this», то unzip test.txt.zip приводит к try.txt с «this» в нем.

Сценарий 2: if test.txtимеет больший объем данных (более 10 байт), например, «это тест на сжатиеположить поток, и он не работает ", то unzip test.txt.zip выдает try.txt с поврежденными фрагментами данных и является неполным.

эти 10 байт - это размер буфера в testZipBytes и объем данных, сжатых привремя по zipBytes

Ожидаемое (или, скорее, желаемое): 1. unzip test.txt.zip не использует имя файла «try.txt», которое я дал в MemoryFile, а скорее распаковывает файл с именем test.txt. 2. разархивированные данные не ломаются и выдают входные данные как есть. 3. Я сделал то же самое с GzipOutputStream, и он отлично работает.

1 Ответ

0 голосов
/ 05 октября 2019

Требование: сжать байт [], чтобы получить другой байт [], используя java.util.zip.ZipOutputStream, НО без использования каких-либо файлов на диске или в памяти (как здесь https://stackoverflow.com/a/18406927/9132186). Это дажевозможно?

Да, вы уже сделали это. На самом деле вам не нужен MemoryFile в вашем примере, просто удалите его из своей реализации и напишите ZipEntry entry = new ZipEntry("try.txt") вместо.

Но вы не можете объединить zip-файлы размером 10 МБ и получить действительный zip-файл для объединенного файла. Zipping работает не так. У вас может быть решение, которое минимизирует объем памяти одновременно, возможноНо разбить оригинальный файл на куски кажется неработоспособным.

...