Лучший способ определить, заархивирован ли поток на Java

StackOverflow https://stackoverflow.com/questions/1809007

  •  05-07-2019
  •  | 
  •  

Вопрос

Каков наилучший способ узнать, что я java.io.InputStream содержит архивированные данные?

Это было полезно?

Решение

магические байты для формата ZIP составляют 50 4B . Вы можете протестировать поток (используя пометку и сброс - вам может понадобиться буферизовать ), но Я не ожидал бы, что это будет 100% надежный подход. Не будет никакого способа отличить его от текстового файла в кодировке US-ASCII, который начинается с букв PK .

Наилучшим способом было бы предоставить метаданные в формате содержимого до открытия потока и затем обработать его соответствующим образом.

Другие советы

Введение

Поскольку всем ответам 5-летней давности, я считаю своим долгом записать, что происходит сегодня.Я серьезно сомневаюсь, что стоит читать магические байты потока!Это низкоуровневый код, его вообще следует избегать.

Простой ответ

мику пишет:

Если поток может быть прочитан через ZipInputStream, он должен быть заархивирован.

Да, но в случае ZipInputStream "может быть прочитан" означает, что первый вызов .getNextEntry() возвращает ненулевое значение.Никаких исключений из правил и так далее.Итак, вместо синтаксического анализа магических байтов вы можете просто сделать:

boolean isZipped = new ZipInputStream(yourInputStream).getNextEntry() != null;

И это все!

Общие мысли о распаковке

В общем, оказалось, что работать с файлами во время [распаковки] архивирования гораздо удобнее, чем с потоками.Существует несколько полезных библиотек, плюс ZipFile обладает большей функциональностью, чем ZipInputStream.Обработка zip-файлов обсуждается здесь: Что такое хорошая библиотека Java для архивирования / распаковки файлов? Так что, если вы умеете работать с файлами, вам лучше это сделать!

Пример кода

Мне нужно было в моем приложении работать только с потоками.Итак, это метод, который я написал для распаковки:

import org.apache.commons.io.IOUtils;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public boolean unzip(InputStream inputStream, File outputFolder) throws IOException {

    ZipInputStream zis = new ZipInputStream(inputStream);

    ZipEntry entry;
    boolean isEmpty = true;
    while ((entry = zis.getNextEntry()) != null) {
        isEmpty = false;
        File newFile = new File(outputFolder, entry.getName());
        if (newFile.getParentFile().mkdirs() && !entry.isDirectory()) {
            FileOutputStream fos = new FileOutputStream(newFile);
            IOUtils.copy(zis, fos);
            IOUtils.closeQuietly(fos);
        }
    }

    IOUtils.closeQuietly(zis);
    return !isEmpty;
}

Вы можете проверить, что первые четыре байта потока являются локальной подписью заголовка файла , которая запускает локальный заголовок файла , который обрабатывает каждый файл в файле ZIP, < a href = "http://www.pkware.com/documents/casestudies/APPNOTE.TXT" rel = "noreferrer">, как показано в спецификации здесь , чтобы быть 50 4B 03 04 .

Небольшой тестовый код показывает, как это работает:

byte[] buffer = new byte[4];

try {
    ZipOutputStream zos = new ZipOutputStream(new FileOutputStream("so.zip"));
    ZipEntry ze = new ZipEntry("HelloWorld.txt");
    zos.putNextEntry(ze);
    zos.write("Hello world".getBytes());
    zos.close();

    FileInputStream is = new FileInputStream("so.zip");
    is.read(buffer);
    is.close();
}
catch(IOException e) {
    e.printStackTrace();
}

for (byte b : buffer) { 
    System.out.printf("%H ",b);
}

Дали мне этот вывод:

50 4B 3 4 

Не очень элегантно, но надежно:

Если поток можно прочитать через ZipInputStream , он должен быть заархивирован.

Проверка магического числа может быть неправильным вариантом.

Файлы Docx также имеют похожее магическое число 50 4B 3 4

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top