2013-03-27 2 views
38

Я пытаюсь создать простую java-программу, которая считывает и извлекает содержимое из файла (ов) внутри zip-файла. Zip-файл содержит 3 файла (txt, pdf, docx). Мне нужно прочитать содержимое всех этих файлов, и для этой цели я использую Apache Tika.Чтение содержимого из файлов, находящихся внутри Zip-файла

Может кто-нибудь помочь мне здесь, чтобы достичь функциональности. Я попытался это до сих пор, но никакого успеха

Код сниппета

public class SampleZipExtract { 


    public static void main(String[] args) { 

     List<String> tempString = new ArrayList<String>(); 
     StringBuffer sbf = new StringBuffer(); 

     File file = new File("C:\\Users\\xxx\\Desktop\\abc.zip"); 
     InputStream input; 
     try { 

      input = new FileInputStream(file); 
      ZipInputStream zip = new ZipInputStream(input); 
      ZipEntry entry = zip.getNextEntry(); 

      BodyContentHandler textHandler = new BodyContentHandler(); 
      Metadata metadata = new Metadata(); 

      Parser parser = new AutoDetectParser(); 

      while (entry!= null){ 

       if(entry.getName().endsWith(".txt") || 
          entry.getName().endsWith(".pdf")|| 
          entry.getName().endsWith(".docx")){ 
       System.out.println("entry=" + entry.getName() + " " + entry.getSize()); 
        parser.parse(input, textHandler, metadata, new ParseContext()); 
        tempString.add(textHandler.toString()); 
       } 
      } 
      zip.close(); 
      input.close(); 

      for (String text : tempString) { 
      System.out.println("Apache Tika - Converted input string : " + text); 
      sbf.append(text); 
      System.out.println("Final text from all the three files " + sbf.toString()); 
     } catch (FileNotFoundException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (SAXException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (TikaException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 
} 
+1

Почему бы не передать почтовый файл прямо на Apache Tika? Затем он вызовет рекурсивный синтаксический анализатор, который вы подаете для каждого файла в zip-файле, поэтому вам не нужно ничего особенного! – Gagravarr

+0

Вот что мне было интересно, но я не мог получить достаточно учебника, как это сделать. Я также немного беспокоюсь об этом - http://www.javamex.com/tutorials/compression/zip_problems.shtml, не уверен, что Tika обратится к этой проблеме. –

+0

Тика использует компромисс, чтобы обойти многие из этих проблем. – Gagravarr

ответ

107

Если вам интересно, как получить содержимое файла с каждого ZipEntry, это на самом деле довольно просто. Вот пример кода:

public static void main(String[] args) throws IOException { 
    ZipFile zipFile = new ZipFile("C:/test.zip"); 

    Enumeration<? extends ZipEntry> entries = zipFile.entries(); 

    while(entries.hasMoreElements()){ 
     ZipEntry entry = entries.nextElement(); 
     InputStream stream = zipFile.getInputStream(entry); 
    } 
} 

После того, как у вас есть InputStream, вы можете прочитать его, как хотите.

+10

Не забудьте закрыть входной поток и ZipFile, чтобы избежать утечки ресурсов :). – Noremac

+2

zipFile.entries(); нет функции записи, определенной для типа zipFile –

+1

Есть ли способ передать массив byte [] в конструктор 'ZipFile (content.getBytes())'? если нет, то как мы можем это сделать? –

9

Из условия в while, петля никогда не может нарушать:

while (entry != null) { 
    // If entry never becomes null here, loop will never break. 
} 

Вместо этого null проверки там , вы можете попробовать следующее:

ZipEntry entry = null; 
while ((entry = zip.getNextEntry()) != null) { 
    // Rest of your code 
} 
+0

Спасибо, что указали на ошибку во время цикла. –

3

Образец кода, который вы можете использовать, чтобы Tika позаботилась о файлах контейнера для вас. http://wiki.apache.org/tika/RecursiveMetadata

Форма, что я могу сказать, принятое решение не будет работать для случаев, когда есть вложенные файлы ZIP. Тика, однако, позаботится и о таких ситуациях.

1

Мой путь достижения этой цели является создание ZipInputStream класса оберточную, что бы справиться с этим будет обеспечивать только поток текущей записи:

Обертка класс:

public class ZippedFileInputStream extends InputStream { 

    private ZipInputStream is; 

    public ZippedFileInputStream(ZipInputStream is){ 
     this.is = is; 
    } 

    @Override 
    public int read() throws IOException { 
     return is.read(); 
    } 

    @Override 
    public void close() throws IOException { 
     is.closeEntry(); 
    } 

}

Использование из него:

ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream("SomeFile.zip")); 

    while((entry = zipInputStream.getNextEntry())!= null) { 

    ZippedFileInputStream archivedFileInputStream = new ZippedFileInputStream(zipInputStream); 

    //... perform whatever logic you want here with ZippedFileInputStream 

    // note that this will only close the current entry stream and not the ZipInputStream 
    archivedFileInputStream.close(); 

    } 
    zipInputStream.close(); 

Одно из преимуществ этого подход: InputStreams передаются как аргументы методам, которые обрабатывают их, и эти методы имеют тенденцию сразу закрыть входной поток после того, как они будут выполнены с ним.

25

Начиная с Java 7, NIO Api обеспечивает лучший и более общий способ доступа к содержимому файлов Zip или Jar. Фактически, теперь это унифицированный API, который позволяет обрабатывать Zip-файлы в точности как обычные файлы.

Для того, чтобы извлечь все файлы, содержащиеся внутри архива в этом API, вы могли бы сделать это:

В Java 8:

private void extractAll(URI fromZip, Path toDirectory) throws IOException{ 
    FileSystems.newFileSystem(fromZip, Collections.emptyMap()) 
      .getRootDirectories() 
      .forEach(root -> { 
       // in a full implementation, you'd have to 
       // handle directories 
       Files.walk(root).forEach(path -> Files.copy(path, toDirectory)); 
      }); 
} 

В Java 7:

private void extractAll(URI fromZip, Path toDirectory) throws IOException{ 
    FileSystem zipFs = FileSystems.newFileSystem(fromZip, Collections.emptyMap()); 

    for(Path root : zipFs.getRootDirectories()) { 
     Files.walkFileTree(root, new SimpleFileVisitor<Path>() { 
      @Override 
      public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) 
        throws IOException { 
       // You can do anything you want with the path here 
       Files.copy(file, toDirectory); 
       return FileVisitResult.CONTINUE; 
      } 

      @Override 
      public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) 
        throws IOException { 
       // In a full implementation, you'd need to create each 
       // sub-directory of the destination directory before 
       // copying files into it 
       return super.preVisitDirectory(dir, attrs); 
      } 
     }); 
    } 
} 
+2

Это оба удивительно и безумно. – Esko

+0

'FileSystem' должен быть закрыт после операции. –

+0

В версии java 8 'Files.walk (root)' вызывает IOException, которое не может распространяться через лямбда. – Barteks2x

Смежные вопросы