2013-03-27 26 views
38

zipファイル内のファイルからコンテンツを読み込んで抽出する簡単なJavaプログラムを作成しようとしています。 Zipファイルには3つのファイル(txt、pdf、docx)が含まれています。私はこれらすべてのファイルの内容を読む必要があり、このためにApache Tikaを使用しています。Zipファイル内のファイルから内容を読み取る

誰かがここで機能を達成するために私を助けることができますか?私はこれまでのところ、これを試してみましたが、そのためwhileにおける条件のない成功

コードスニペット

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

Tikaはこれらの問題の多くを回避するためにcommons compressを使用します – 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); 
    } 
} 

一度あなたがそれを読んでもよいです。

+10

リソースリークを避けるために、inputStreamとZipFileを閉じるのを忘れないでください:)。 – Noremac

+2

zipFile.entries(); zipFile型のエントリ関数が定義されていません –

+1

byte []配列を 'ZipFile(content.getBytes())'のコンストラクタに渡す方法はありますか?どうすればいい? –

9

は、ループが壊れることはありませんかもしれません。その代わりnullチェックの

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

がこれを試すことができます:

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

whileループの間違いを指摘してくれてありがとう。 –

3

サンプルコードを使用して、Tikaがコンテナファイルを世話するようにすることができます。

私が知る限り、ネストされた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(); 

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

25

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); 
      } 
     }); 
    } 
} 
+2

これはすばらしいことであり、狂気です。 – Esko

+0

'FileSystem'は操作の後に閉じなければなりません。 –

+0

java 8バージョンでは、 'Files.walk(root)'はラムダを伝播できないIOExceptionをスローします。 – Barteks2x

関連する問題