Чтение содержимого из файлов, находящихся внутри Zip-файла
Я пытаюсь создать простую программу java, которая читает и извлекает содержимое из файла(ов) внутри zip-файла. Zip-файл содержит 3 файла (txt, pdf, docx). Мне нужно прочитать содержимое всех этих файлов и я использую Apache Tika для этой цели.
может кто-нибудь помочь мне здесь, чтобы достичь функциональности. Я пробовал это до сих пор, но безуспешно
Код
public class SampleZipExtract {
    public static void main(String[] args) {
        List<String> tempString = new ArrayList<String>();
        StringBuffer sbf = new StringBuffer();
        File file = new File("C:UsersxxxDesktopabc.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();
        }
    }
}
5 ответов
Если вам интересно, как получить содержимое файла от каждого 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 вы можете прочитать его, как хотите.
начиная с Java 7, Api NIO обеспечивает лучший и более общий способ доступа к содержимому Zip или JAR-файлов. На самом деле, теперь это унифицированный API, который позволяет обрабатывать Zip-файлы точно так же, как обычные файлы.
чтобы извлечь все файлы, содержащиеся внутри 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);
            }
        });
    }
}
из-за состояния в 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
}
пример кода, который вы можете использовать, чтобы позволить Tika заботиться о файлах контейнеров для вас. http://wiki.apache.org/tika/RecursiveMetadata
форма, что я могу сказать, принятое решение не будет работать для случаев, когда есть вложенные zip-файлы. Тика, однако, позаботится и о таких ситуациях.
мой способ достичь этого-создать класс обертывания 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 передаются в качестве аргументов методов, и эти методы имеют тенденцию немедленно закрыть входной поток после того, как они сделали с ним.
