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

时间:2022-05-24 22:37:31

I am trying to create a simple java program which reads and extracts the content from the file(s) inside zip file. Zip file contains 3 files (txt, pdf, docx). I need to read the contents of all these files and I am using Apache Tika for this purpose.

我正在尝试创建一个简单的java程序,它从zip文件中的文件中读取和提取内容。 Zip文件包含3个文件(txt,pdf,docx)。我需要阅读所有这些文件的内容,我正在使用Apache Tika。

Can somebody help me out here to achieve the functionality. I have tried this so far but no success

有人可以帮我在这里实现功能。到目前为止我已经尝试过但没有成功

Code Snippet

代码片段

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();
        }
    }
}

5 个解决方案

#1


114  

If you're wondering how to get the file content from each ZipEntry it's actually quite simple. Here's a sample code:

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

Once you have the InputStream you can read it however you want.

一旦你有了InputStream,你可以随意阅读它。

#2


27  

As of Java 7, the NIO Api provides a better and more generic way of accessing the contents of Zip or Jar files. Actually, it is now a unified API which allows you to treat Zip files exactly like normal files.

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

In order to extract all of the files contained inside of a zip file in this API, you'd do this:

要在此API中提取zip文件中包含的所有文件,您需要执行以下操作:

In Java 8:

在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));
            });
}

In java 7:

在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);
            }
        });
    }
}

#3


10  

Because of the condition in while, the loop might never break:

由于while中的条件,循环可能永远不会中断:

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

Instead of the null check there, you can try this:

而不是那里的空检查,你可以试试这个:

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

#4


3  

Sample code you can use to let Tika take care of container files for you. http://wiki.apache.org/tika/RecursiveMetadata

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

Form what I can tell, the accepted solution will not work for cases where there are nested zip files. Tika, however will take care of such situations as well.

从我所知的形式来看,接受的解决方案不适用于存在嵌套zip文件的情况。然而,蒂卡也将照顾这种情况。

#5


1  

My way of achieving this is by creating ZipInputStream wrapping class that would handle that would provide only the stream of current entry:

我实现这一点的方法是创建ZipInputStream包装类,它将处理只提供当前条目流的包:

The wrapper class:

包装类:

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();
    }

}

}

The use of it:

使用它:

    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();

One advantage of this approach: InputStreams are passed as an arguments to methods that process them and those methods have a tendency to immediately close the input stream after they are done with it.

这种方法的一个优点是:InputStreams作为参数传递给处理它们的方法,并且这些方法在完成后立即关闭输入流。

#1


114  

If you're wondering how to get the file content from each ZipEntry it's actually quite simple. Here's a sample code:

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

Once you have the InputStream you can read it however you want.

一旦你有了InputStream,你可以随意阅读它。

#2


27  

As of Java 7, the NIO Api provides a better and more generic way of accessing the contents of Zip or Jar files. Actually, it is now a unified API which allows you to treat Zip files exactly like normal files.

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

In order to extract all of the files contained inside of a zip file in this API, you'd do this:

要在此API中提取zip文件中包含的所有文件,您需要执行以下操作:

In Java 8:

在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));
            });
}

In java 7:

在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);
            }
        });
    }
}

#3


10  

Because of the condition in while, the loop might never break:

由于while中的条件,循环可能永远不会中断:

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

Instead of the null check there, you can try this:

而不是那里的空检查,你可以试试这个:

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

#4


3  

Sample code you can use to let Tika take care of container files for you. http://wiki.apache.org/tika/RecursiveMetadata

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

Form what I can tell, the accepted solution will not work for cases where there are nested zip files. Tika, however will take care of such situations as well.

从我所知的形式来看,接受的解决方案不适用于存在嵌套zip文件的情况。然而,蒂卡也将照顾这种情况。

#5


1  

My way of achieving this is by creating ZipInputStream wrapping class that would handle that would provide only the stream of current entry:

我实现这一点的方法是创建ZipInputStream包装类,它将处理只提供当前条目流的包:

The wrapper class:

包装类:

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();
    }

}

}

The use of it:

使用它:

    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();

One advantage of this approach: InputStreams are passed as an arguments to methods that process them and those methods have a tendency to immediately close the input stream after they are done with it.

这种方法的一个优点是:InputStreams作为参数传递给处理它们的方法,并且这些方法在完成后立即关闭输入流。