Каков наилучший способ узнать, что я java.io.InputStream
содержит сжатые данные?
Лучший способ определить, если поток застрял в Java
Ответ 1
магические байты для формата ZIP 50 4B
. Вы можете протестировать поток (используя mark и reset - вам может понадобиться buffer), но я бы не ожидал, что это будет 100% надежный подход. Невозможно отличить его от текстового файла с кодировкой US-ASCII, который начинался с букв PK
.
Лучший способ - предоставить метаданные в формате содержимого до открытия потока, а затем обработать его соответствующим образом.
Ответ 2
Введение
Поскольку все ответы 5 лет, я чувствую обязанность записать, что происходит сегодня. Я серьезно сомневаюсь, что нужно читать магические байты потока! Что код низкого уровня, его следует избегать в целом.
Простой ответ
miku пишет:
Если поток можно прочитать через ZipInputStream, он должен быть заархивирован.
Да, но в случае ZipInputStream
"можно прочитать" означает, что первый вызов .getNextEntry()
возвращает ненулевое значение. Никакое исключение не улавливается и так далее. Поэтому вместо магии синтаксического анализа байтов вы можете просто:
boolean isZipped = new ZipInputStream(yourInputStream).getNextEntry() != null;
И что это!
Общие расстегивающие мысли
В общем, оказалось, что гораздо удобнее работать с файлами в то время как [un] zipping, чем с потоками. Существует несколько полезных библиотек, плюс ZipFile имеет больше функциональности, чем ZipInputStream. Обработка zip файлов обсуждается здесь: Что такое хорошая библиотека Java для zip/unzip файлов? Поэтому, если вы можете работать с файлами, вам лучше делать это!
Пример кода
Мне нужно было в моем приложении работать только с потоками. Так что метод, который я написал для распаковки:
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;
}
Ответ 3
Вы можете проверить, что первые четыре байта потока являются сигнатурой заголовка локального файла, которая запускает заголовок локального файла, который обрабатывает каждый файл в ZIP файле, как показано в спецификации здесь, будет 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
Ответ 4
Не очень элегантный, но надежный:
Если поток можно прочитать через ZipInputStream
, он должен быть заархивирован.
Ответ 5
Проверка магического номера может оказаться неправильной.
Файлы Docx также имеют аналогичное магическое число 50 4B 3 4
Ответ 6
Поскольку и .zip, и .xlsx имеют одно и то же магическое число, я не смог найти действительный zip файл (если его переименовали).
Итак, я использовал Apache Tika, чтобы найти точный тип документа.
Даже если переименовать тип файла в zip, он находит точный тип.