66

如何在 Java 中提取 tar(或 tar.gz 或 tar.bz2)文件?

4

8 回答 8

74

您可以使用 Apache Commons Compress 库来执行此操作。您可以从http://mvnrepository.com/artifact/org.apache.commons/commons-compress/1.2下载 1.2 版本。

这里有两种方法:一种是解压缩文件,另一种是解压缩文件。因此,对于文件 <fileName>tar.gz,您需要先解压缩它,然后再解压缩它。请注意,tar 存档也可能包含文件夹,在这种情况下需要在本地文件系统上创建它们。

享受。

/** 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;
}
于 2011-09-26T14:05:15.840 回答
22

注意:此功能后来通过一个单独的项目 Apache Commons Compress 发布,如另一个答案中所述。这个答案已经过时了。


我没有直接用过 tar API,但是 tar 和 bzip2 是在 Ant 中实现的;你可以借用他们的实现,或者可能使用 Ant 来做你需要的事情。

Gzip 是 Java SE 的一部分(我猜 Ant 的实现遵循相同的模型)。

GZIPInputStream只是一个InputStream装饰器。例如,您可以将 a 包装FileInputStream在 a 中GZIPInputStream,并以与使用 any 相同的方式使用它InputStream

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

(请注意,GZIPInputStream 有自己的内部缓冲区,因此将其包装FileInputStream在 aBufferedInputStream中可能会降低性能。)

于 2008-11-24T22:00:41.743 回答
13

Apache Commons VFS支持 tar 作为一种虚拟文件系统,它支持这样的 URLtar:gz:http://anyhost/dir/mytar.tar.gz!/mytar.tar!/path/in/tar/README.txt

TrueZip或其继任者TrueVFS 也是如此……它也可以从 Maven Central 获得。

于 2010-11-12T13:30:10.607 回答
13
Archiver archiver = ArchiverFactory.createArchiver("tar", "gz");
archiver.extract(archiveFile, destDir);

依赖:

 <dependency>
        <groupId>org.rauschig</groupId>
        <artifactId>jarchivelib</artifactId>
        <version>0.5.0</version>
</dependency>
于 2014-03-18T14:04:08.240 回答
8

我只是尝试了一堆建议的库(TrueZip、Apache Compress),但没有运气。

以下是 Apache Commons VFS 的示例:

FileSystemManager fsManager = VFS.getManager();
FileObject archive = fsManager.resolveFile("tgz:file://" + fileName);

// List the children of the archive file
FileObject[] children = archive.getChildren();
System.out.println("Children of " + archive.getName().getURI()+" are ");
for (int i = 0; i < children.length; i++) {
    FileObject fo = children[i];
    System.out.println(fo.getName().getBaseName());
    if (fo.isReadable() && fo.getType() == FileType.FILE
        && fo.getName().getExtension().equals("nxml")) {
        FileContent fc = fo.getContent();
        InputStream is = fc.getInputStream();
    }
}

和maven依赖:

    <dependency>
      <groupId>commons-vfs</groupId>
      <artifactId>commons-vfs</artifactId>
      <version>1.0</version>
    </dependency>
于 2011-09-23T21:17:43.633 回答
6

除了 gzip 和 bzip2,Apache Commons Compress API还支持 tar,最初基于ICE Engineering Java Tar Package,它既是 API 又是独立工具。

于 2010-11-12T13:19:00.563 回答
4

将这个API用于 tar 文件,另一个包含在 Ant 中的 BZIP2 和标准的 GZIP 的 API 怎么样?

于 2008-11-24T21:55:04.767 回答
2

这是一个基于Dan Borza早期回答的版本,它使用Apache Commons Compress和 Java NIO(即路径而不是文件)。它还在一个流中进行解压缩和解压缩,因此无需创建中间文件。

public static void unTarGz( Path pathInput, Path pathOutput ) throws IOException {
    TarArchiveInputStream tararchiveinputstream =
        new TarArchiveInputStream(
            new GzipCompressorInputStream(
                new BufferedInputStream( Files.newInputStream( pathInput ) ) ) );

    ArchiveEntry archiveentry = null;
    while( (archiveentry = tararchiveinputstream.getNextEntry()) != null ) {
        Path pathEntryOutput = pathOutput.resolve( archiveentry.getName() );
        if( archiveentry.isDirectory() ) {
            if( !Files.exists( pathEntryOutput ) )
                Files.createDirectory( pathEntryOutput );
        }
        else
            Files.copy( tararchiveinputstream, pathEntryOutput );
    }

    tararchiveinputstream.close();
}
于 2019-02-22T16:06:55.240 回答