2013-03-27 13 views
38

Sto cercando di creare un semplice programma java che legge ed estrae il contenuto dal file (s) all'interno del file zip. Il file zip contiene 3 file (txt, pdf, docx). Ho bisogno di leggere il contenuto di tutti questi file e sto usando Apache Tika per questo scopo.Leggi contenuto da file che si trovano all'interno del file zip

Qualcuno può aiutarmi qui per ottenere la funzionalità. Ho provato questo finora, ma senza successo

frammento di codice

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

Perché non passare il file zip direttamente ad Apache Tika? Quindi chiamerà il parser ricorsivo che fornisci per ogni file nello zip, quindi non devi fare nulla di speciale! – Gagravarr

+0

Questo è quello che mi stavo chiedendo ma non ho potuto ottenere abbastanza tutorial su come farlo. Sono anche un po 'preoccupato per questo - http://www.javamex.com/tutorials/compression/zip_problems.shtml, non sono sicuro che Tika risolva questo problema. –

+0

Tika utilizza i comuni compressi per aggirare un sacco di questi problemi – Gagravarr

risposta

107

Se ti stai chiedendo come ottenere il contenuto del file da ogni ZipEntry è in realtà abbastanza semplice. Ecco un codice di esempio:

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

Una volta che avete InputStream potete leggerlo come volete.

+10

Non dimenticare di chiudere inputStream e ZipFile per evitare perdite di risorse :). – Noremac

+2

zipFile.entries(); non esiste una funzione definita per il tipo zipFile –

+1

C'è un modo per passare l'array di byte [] al costruttore di 'ZipFile (content.getBytes())'? se no come possiamo farlo? –

9

A causa della condizione in while, il ciclo potrebbe mai spezzare:

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

Al posto del controllo null lì , puoi provare questo:

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

Grazie per aver segnalato l'errore durante il ciclo. –

3

Codice di esempio che puoi utilizzare per consentire a Tika di occuparsi dei file contenitore per te. http://wiki.apache.org/tika/RecursiveMetadata

Form quello che posso dire, la soluzione accettata non funzionerà per i casi in cui ci sono file zip annidati. Tika, tuttavia, si prenderà cura anche di queste situazioni.

1

Il mio modo di raggiungere tale scopo è la creazione di ZipInputStream classe involucro che avrebbe gestito che avrebbe fornito solo il flusso di entrata corrente:

La classe wrapper:

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

}

L'uso di esso:

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

Un vantaggio di questo approccio: InputStreams viene passato come argomento ai metodi che li elaborano e quei metodi hanno la tendenza a chiudere immediatamente il flusso di input dopo averlo fatto.

25

A partire da Java 7, NIO Api fornisce un modo migliore e più generico di accedere ai contenuti dei file Zip o Jar. In realtà, ora è un'API unificata che consente di trattare i file Zip esattamente come i file normali.

Per estrarre tutti i file contenuti all'interno di un file zip in questa API, faresti questo:

In 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:

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

Questo è sia fantastico che folle. – Esko

+0

'FileSystem' deve essere chiuso dopo l'operazione. –

+0

Nella versione java 8, 'Files.walk (root)' genera IOException che non può propagarsi attraverso il lambda. – Barteks2x

Problemi correlati