Утилитная библиотека Java для обработки вложенных ZIP-файлов

Мне известно, что Oracle отмечает методы сжатия/распаковки файлов ZIP/GZIP на своем веб-сайте. . Но у меня есть сценарий, в котором мне нужно сканировать и выяснить, задействованы ли какие-либо вложенные ZIP/RAR. Например, следующий случай:

-MyFiles.zip
   -MyNestedFiles.zip
        -MyMoreNestedFiles.zip
           -MoreProbably.zip
        -Other_non_zips
   -Other_non_zips
-Other_non_zips

Я знаю, что пакет сжатия apache commons и java.util.zip являются широко используемыми пакетами, где сжатие commons фактически обслуживает отсутствующие функции в java.util.zip, например. некоторые настройки символов при выполнении zipouts. Но в чем я не уверен, так это в утилитах для рекурсии через вложенные zip-файлы, и ответы, предоставленные на SO, не являются очень хорошими примерами этого. Я попробовал следующий код (который я получил из блога Oracle), но, как я и подозревал, рекурсия вложенного каталога терпит неудачу, потому что она просто не может найти файлы:

public static void processZipFiles(String pathName) throws Exception{
        ZipInputStream zis  = null;
        InputStream  is = null;
        try {
          ZipFile zipFile = new ZipFile(new File(pathName));
          String nestPathPrefix = zipFile.getName().substring(0, zipFile.getName().length() -4);
          for(Enumeration e = zipFile.entries(); e.hasMoreElements();){
           ZipEntry ze = (ZipEntry)e.nextElement();
            if(ze.getName().contains(".zip")){
              is = zipFile.getInputStream(ze);
              zis = new ZipInputStream(is);
              ZipEntry zentry = zis.getNextEntry();

              while (zentry!=null){
                  System.out.println(zentry.getName());
                  zentry = zis.getNextEntry();
                  ZipFile nestFile = new ZipFile(nestPathPrefix+"\\"+zentry.getName());
                  if (zentry.getName().contains(".zip")) {
                      processZipFiles(nestPathPrefix+"\\"+zentry.getName());
                  }
              }
              is.close();
            }
          }
        } catch (FileNotFoundException e) {
          e.printStackTrace();
        } catch (IOException e) {
          e.printStackTrace();
        } finally{
            if(is != null)
                is.close();
            if(zis!=null)
                zis.close();
        }
    }  

Может я что-то не так делаю или использую не те утилиты. Моя цель - определить, есть ли у каких-либо файлов или вложенных zip-файлов расширения файлов, которые я не разрешаю. Это сделано для того, чтобы я мог запретить своим пользователям загружать запрещенные файлы, даже когда они их архивируют. У меня также есть возможность использовать Tika, который может выполнять рекурсивный анализ (используя решение Zukka Zitting), но я не уверен, смогу ли я использовать метаданные для этого обнаружения, как я хочу.

Любая помощь/предложение приветствуется.


person ha9u63ar    schedule 11.02.2016    source источник
comment
Разве вы не должны открывать Nested Zip из входного потока внешней записи zip, а не по имени файла (что не будет работать, поскольку файл находится в zip, а не в файловой системе)?   -  person Gagravarr    schedule 11.02.2016


Ответы (1)


Использование Commons Compress было бы проще, не в последнюю очередь потому, что он имеет разумные общие интерфейсы между различными декомпрессорами, которые облегчают жизнь + позволяют одновременно обрабатывать другие форматы сжатия (например, Tar).

Если вы хотите использовать только встроенную поддержку Zip, я бы посоветовал вам сделать что-то вроде этого:

File file = new File("outermost.zip");
FileInputStream input = new FileInputStream(file);
check(input, file.toString());

public static void check(InputStream compressedInput, String name) {
   ZipInputStream input = new ZipInputStream(compressedInput);
   ZipEntry entry = null;
   while ( (entry = input.getNextEntry()) != null ) {
      System.out.println("Found " + entry.getName() + " in " + name);
      if (entry.getName().endsWith(".zip")) { // TODO Better checking
         check(input, name + "/" + entry.getName());
      }
   }
}

Ваш код потерпит неудачу, поскольку вы пытаетесь прочитать inner.zip в outer.zip как локальный файл, но он не существует как отдельный файл. Приведенный выше код будет обрабатывать вещи, оканчивающиеся на .zip, как другой zip-файл, и будет рекурсивно

Вы, вероятно, захотите использовать сжатие Commons, чтобы вы могли обрабатывать вещи с альтернативными именами файлов, другими форматами сжатия и т. д.

person Gagravarr    schedule 11.02.2016
comment
Это простое решение, но оно не проходит через .RAR. Я пробовал с Tika, но анализ метаданных занимает довольно много времени (возможно, потому, что он анализирует все это). - person ha9u63ar; 11.02.2016
comment
Я вижу, что могу заменить ZipInputStream на ZipArchiveInputStream, но какой поток я использую для RAR/TAR. Должен ли я держать ArchiveInputStream и ArchiveEntry все время? - person ha9u63ar; 11.02.2016
comment
Если вы хотите работать со всеми форматами с помощью Commons Compress, используйте общие классы архива. Хороший пример этого см. в Исходный код анализатора пакетов Apache Tika - person Gagravarr; 11.02.2016
comment
@Gagravarr Я думаю, проблема в том, что у .RAR есть определенные проблемы с лицензией, которых нет у JDK во встроенных API (и, если уж на то пошло, общие ресурсы тоже не сжимаются), но Tika, похоже, каким-то образом имеет это с помощью других средств. Было бы неплохо узнать, какую библиотеку он использует для RAR и является ли она частью фонда apache. - person ha9u63ar; 11.02.2016
comment
@ ha9u63ar Вы можете найти подробности в pom-файле Apache Tika Parsers — это com.github.junrar / junrar - person Gagravarr; 11.02.2016