84

zip ファイル内のファイルからコンテンツを読み取って抽出する単純な Java プログラムを作成しようとしています。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:\\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();
        }
    }
}
4

6 に答える 6

205

それぞれからファイルの内容を取得する方法を知りたい場合は、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 を取得したら、必要に応じて読み取ることができます。

于 2013-03-27T19:05:25.660 に答える
52

Java 7 の時点で、NIO Api は、Zip または Jar ファイルのコンテンツにアクセスするためのより優れた、より一般的な方法を提供します。実際には、Zip ファイルを通常のファイルとまったく同じように扱うことができる統合 API になりました。

この 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);
            }
        });
    }
}
于 2016-05-24T12:25:57.540 に答える
11

の条件により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
}
于 2013-03-27T19:00:02.077 に答える
3

Tika にコンテナー ファイルを処理させるために使用できるサンプル コード。 http://wiki.apache.org/tika/RecursiveMetadata

私が知る限り、受け入れられた解決策は、ネストされた zip ファイルがある場合には機能しません。しかし、ティカはそのような状況にも対処します。

于 2013-12-24T22:38:57.187 に答える
2

これを実現する私の方法は、現在のエントリのストリームのみを提供する処理を行う 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();

このアプローチの利点の 1 つは、InputStreams がそれらを処理するメソッドに引数として渡されることです。これらのメソッドは、処理が完了した後、入力ストリームをすぐに閉じる傾向があります。

于 2016-02-19T16:46:07.437 に答える