从Zip文件中的文件读取内容

从Zip文件中的文件读取内容

问题描述:

我想创建一个简单的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

为什么不直接将zip文件传给Apache Tika?然后它会调用你为zip中每个文件提供的递归解析器,所以你不必做任何特别的事情! – Gagravarr 2013-03-28 04:20:43

+0

这就是我想知道的,但无法获得足够的教程在如何做到这一点。我也对此一点担心 - http://www.javamex.com/tutorials/compression/zip_problems.shtml,不知道如果Tika解决这个问题。 – 2013-03-28 06:42:01

+0

Tika使用commons compress来解决很多这些问题 – Gagravarr 2013-03-28 06:48:17

如果您想知道如何从每个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

不要忘记关闭inputStream和ZipFile以避免资源泄漏:)。 – Noremac 2014-07-24 20:51:15

+2

zipFile.entries();有没有为类型zipFile定义的条目函数 – 2014-08-20 02:32:08

+1

有没有办法将byte []数组传递给'ZipFile(content.getBytes())'的构造函数?如果不是,我们该怎么做? – 2014-10-31 12:47:42

由于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

感谢您指出while循环中的错误。 – 2013-03-27 19:10:34

您可以使用示例代码让Tika为您处理容器文件。 http://wiki.apache.org/tika/RecursiveMetadata

形式我可以告诉,接受的解决方案将不适用于嵌套zip文件的情况下。不过,Tika也会照顾到这种情况。

我实现这一目标的方法是通过创建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作为参数传递给处理它们的方法,这些方法倾向于在完成输入流后立即关闭输入流。

从Java 7开始,NIO Api提供了一种更好,更通用的方式来访问Zip或Jar文件的内容。实际上,它现在是一个统一的API,它允许您像处理普通文件一样处理Zip文件。

为了提取包含的所有该API的zip文件里的文件,你可以这样做:

在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 2016-10-24 09:53:51

+0

操作完成后'FileSystem'应该关闭。 – 2017-12-30 19:20:40

+0

在java 8版本中,'Files.walk(root)'抛出IOException,它不能通过lambda传播。 – Barteks2x 2018-01-03 22:55:18