85 votes

Lire le contenu des fichiers qui se trouvent dans un fichier Zip

J'essaie de créer un programme Java simple qui lit et extrait le contenu des fichiers à l'intérieur d'un fichier zip. Le fichier zip contient 3 fichiers (txt, pdf, docx). J'ai besoin de lire le contenu de tous ces fichiers et j'utilise Apache Tika à cette fin.

Quelqu'un peut-il m'aider à réaliser cette fonctionnalité ? J'ai déjà essayé, mais sans succès

Extrait de code

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

207voto

Rodrigo Sasaki Points 1944

Si vous vous demandez comment obtenir le contenu des fichiers de chaque ZipEntry c'est en fait assez simple. Voici un exemple de code :

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

Une fois que vous avez le InputStream, vous pouvez le lire comme vous le souhaitez.

52voto

LordOfThePigs Points 3853

Depuis Java 7, l'API NIO offre une manière plus générique d'accéder au contenu des fichiers Zip ou Jar. En fait, il s'agit maintenant d'une API unifiée qui vous permet de traiter les fichiers Zip exactement comme des fichiers normaux.

Pour extraire tous les fichiers contenus dans un fichier zip dans cette API, vous devez procéder comme suit :

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

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

11voto

En raison de la condition dans while La boucle pourrait ne jamais être rompue :

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

Au lieu de la null Vérifiez là, vous pouvez essayer ceci :

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

3voto

Harinder Points 122

Exemple de code que vous pouvez utiliser pour laisser Tika s'occuper des fichiers de conteneurs à votre place. http://wiki.apache.org/tika/RecursiveMetadata

D'après ce que je peux dire, la solution acceptée ne fonctionnera pas dans les cas où il y a des fichiers zip imbriqués. Tika, cependant, s'occupera de ces situations également.

2voto

Vilius Points 77

Pour ce faire, j'ai créé une classe ZipInputStream qui gérerait uniquement le flux de l'entrée courante :

La classe enveloppante :

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'usage qui en est fait :

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

Cette approche présente un avantage : Les InputStreams sont transmis en tant qu'arguments aux méthodes qui les traitent et ces méthodes ont tendance à fermer immédiatement le flux d'entrée une fois qu'elles en ont terminé avec lui.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X