65 votes

Comment extraire un fichier tar en Java ?

Comment extraire un fichier tar (ou tar.gz, ou tar.bz2) en Java ?

0 votes

Skiphoppy, après 2008, date à laquelle j'ai répondu initialement, le projet Apache Commons Compress a été publié. Vous devriez probablement accepter cette réponse pour qu'il soit plus mis en valeur.

73voto

Dan Borza Points 436

Vous pouvez le faire avec la bibliothèque Apache Commons Compress. Vous pouvez télécharger la version 1.2 à partir de http://mvnrepository.com/artifact/org.apache.commons/commons-compress/1.2 .

Voici deux méthodes : une qui décompresse un fichier et une autre qui le détache. Ainsi, pour un fichier <nomdufichier>tar.gz, vous devez d'abord le décompresser et ensuite le désarchiver. Veuillez noter que l'archive tar peut également contenir des dossiers, auquel cas ils doivent être créés sur le système de fichiers local.

Profitez-en.

/** Untar an input file into an output file.

 * The output file is created in the output folder, having the same name
 * as the input file, minus the '.tar' extension. 
 * 
 * @param inputFile     the input .tar file
 * @param outputDir     the output directory file. 
 * @throws IOException 
 * @throws FileNotFoundException
 *  
 * @return  The {@link List} of {@link File}s with the untared content.
 * @throws ArchiveException 
 */
private static List<File> unTar(final File inputFile, final File outputDir) throws FileNotFoundException, IOException, ArchiveException {

    LOG.info(String.format("Untaring %s to dir %s.", inputFile.getAbsolutePath(), outputDir.getAbsolutePath()));

    final List<File> untaredFiles = new LinkedList<File>();
    final InputStream is = new FileInputStream(inputFile); 
    final TarArchiveInputStream debInputStream = (TarArchiveInputStream) new ArchiveStreamFactory().createArchiveInputStream("tar", is);
    TarArchiveEntry entry = null; 
    while ((entry = (TarArchiveEntry)debInputStream.getNextEntry()) != null) {
        final File outputFile = new File(outputDir, entry.getName());
        if (entry.isDirectory()) {
            LOG.info(String.format("Attempting to write output directory %s.", outputFile.getAbsolutePath()));
            if (!outputFile.exists()) {
                LOG.info(String.format("Attempting to create output directory %s.", outputFile.getAbsolutePath()));
                if (!outputFile.mkdirs()) {
                    throw new IllegalStateException(String.format("Couldn't create directory %s.", outputFile.getAbsolutePath()));
                }
            }
        } else {
            LOG.info(String.format("Creating output file %s.", outputFile.getAbsolutePath()));
            final OutputStream outputFileStream = new FileOutputStream(outputFile); 
            IOUtils.copy(debInputStream, outputFileStream);
            outputFileStream.close();
        }
        untaredFiles.add(outputFile);
    }
    debInputStream.close(); 

    return untaredFiles;
}

/**
 * Ungzip an input file into an output file.
 * <p>
 * The output file is created in the output folder, having the same name
 * as the input file, minus the '.gz' extension. 
 * 
 * @param inputFile     the input .gz file
 * @param outputDir     the output directory file. 
 * @throws IOException 
 * @throws FileNotFoundException
 *  
 * @return  The {@File} with the ungzipped content.
 */
private static File unGzip(final File inputFile, final File outputDir) throws FileNotFoundException, IOException {

    LOG.info(String.format("Ungzipping %s to dir %s.", inputFile.getAbsolutePath(), outputDir.getAbsolutePath()));

    final File outputFile = new File(outputDir, inputFile.getName().substring(0, inputFile.getName().length() - 3));

    final GZIPInputStream in = new GZIPInputStream(new FileInputStream(inputFile));
    final FileOutputStream out = new FileOutputStream(outputFile);

    IOUtils.copy(in, out);

    in.close();
    out.close();

    return outputFile;
}

1 votes

Votre exemple est un excellent début, mais il semble que j'aie un problème avec : while ((entry = (TarArchiveEntry)debInputStream.getNextEntry()) != null). Le problème est que lorsque je traite le premier fichier par le biais d'un cadre externe (par exemple SAXBuilder), le flux d'entrée debInputStream est fermé et le deuxième appel de depInputStream.getNextEntry() lève une exception "le tampon d'entrée est fermé".

0 votes

Relié, avec une mise en œuvre similaire : Comment détariser un fichier TAR en utilisant Apache Commons

0 votes

Merci de partager. Il aurait été bien qu'ils mettent une méthode unTar dans la bibliothèque apache compress. Cela semble être une opération fondamentale.

22voto

erickson Points 127945

Note : Cette fonctionnalité a ensuite été publiée dans le cadre d'un projet distinct, Apache Commons Compress, sous le nom de décrite dans une autre réponse. Cette réponse n'est plus d'actualité.


Je n'ai pas utilisé directement une API tar, mais tar et bzip2 sont implémentés dans Ant ; vous pourriez emprunter leur implémentation, ou éventuellement utiliser Ant pour faire ce dont vous avez besoin.

Gzip fait partie de Java SE (et je suppose que l'implémentation de Ant suit le même modèle).

GZIPInputStream est juste un InputStream décorateur. Vous pouvez envelopper, par exemple, un FileInputStream dans un GZIPInputStream et l'utiliser de la même manière que vous utiliseriez n'importe quelle InputStream :

InputStream is = new GZIPInputStream(new FileInputStream(file));

(Notez que le flux d'entrée GZIPInputStream possède son propre tampon interne. FileInputStream dans un BufferedInputStream diminuerait probablement les performances).

2 votes

J'étais sur le point de lui parler de GZIPInputStream. Mais cela ne l'aidera pas, puisqu'il doit toujours lire le fichier .tar contenu :)

1 votes

En réalité, je connais déjà GZIPInputStream, grâce à une autre question que j'ai posée ici. Mais je ne connais rien aux API de tar, et j'espérais qu'il y ait quelque chose qui gère gzip de manière intégrée, donc je ne voulais pas limiter les réponses en disant tout ce que je savais déjà.

3 votes

Les classes Apache regroupées dans 'ant' fonctionnent bien. J'utilise ceci tous les jours : org.apache.tools.tar.TarEntry et org.apache.tools.tar.TarInputStream ; le code est très similaire à celui que vous utiliseriez pour décompresser des fichiers zip. Si vous voulez faire du Bzip2, utilisez jaxlib.

13voto

Jörg Points 810

Apache Commons VFS supporte le tar en tant que système de fichiers virtuel qui prend en charge les URL comme celle-ci tar:gz:[http://anyhost/dir/mytar.tar.gz!/mytar.tar!/path/in/tar/README.txt](http://anyhost/dir/mytar.tar.gz!/mytar.tar!/path/in/tar/README.txt)

TrueZip ou son successeur TrueVFS fait la même chose ... il est également disponible à partir de Maven Central.

13voto

D3iv Points 21
Archiver archiver = ArchiverFactory.createArchiver("tar", "gz");
archiver.extract(archiveFile, destDir);

Dépendance :

 <dependency>
        <groupId>org.rauschig</groupId>
        <artifactId>jarchivelib</artifactId>
        <version>0.5.0</version>
</dependency>

6voto

Jörg Points 810

En plus de gzip et bzip2, Apache Commons Compress API a également soutenu le goudron, initialement basé sur ICE Engineering Java Tar Package qui est à la fois une API et un outil autonome.

1 votes

L'API Apache Commons Compress supporte tar et est basée à l'origine sur le paquet tar ICE ci-dessus, je crois : commons.apache.org/compress

2 votes

Mes tests montrent que ICE tar est le plus rapide parmi les cinq concurrents (ice, compress, ant, xeus + vfs), tandis que Commons Compress arrive en deuxième position ... cependant ICE tar semble un peu moins fiable en ce qui concerne l'exhaustivité du déballage de toutes les entrées et la conservation des noms de fichiers originaux des entrées de l'archive.

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