题 如何在Java中提取tar文件?


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


56
2017-11-24 21:48


起源


skiphoppy,2008年我最初回答之后,Apache Commons Compress项目发布了。你应该接受 这个答案 所以它更突出了。 - erickson


答案:


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


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

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

GZIPInputStream 只是一个 InputStream 装饰。例如,你可以包装一个 FileInputStream 在一个 GZIPInputStream 并以与使用任何方式相同的方式使用它 InputStream

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

(注意,GZIPInputStream有自己的内部缓冲区,所以包装了 FileInputStream 在一个 BufferedInputStream 可能会降低性能。)


18
2017-11-24 22:00



我正准备告诉他关于GZIPInputStream的事。但它不会帮助他,因为他仍然需要阅读包含的.tar文件:) - Johannes Schaub - litb
真相是我已经了解GZIPInputStream,这要归功于我在这里提出的另一个问题。但我对tar API一无所知,我希望有可能以集成的方式处理gzip,所以我不想通过说出我已经知道的内容来限制答案。 - skiphoppy
捆绑在'ant'中的Apache类工作正常。我每天都使用它:org.apache.tools.tar.TarEntry和org.apache.tools.tar.TarInputStream;代码与解压缩zip文件的代码非常相似。如果你想做Bzip2,请使用jaxlib。 - tucuxi
(奇怪的是)这里有Ant / TarInputStream变种的一个很好的例子。 code.google.com/p/jtar  +1使用ant libs btw - jsh
BZIP2的另一个 - stackoverflow.com/questions/2322944/uncompress-bzip2-archive - jsh


您可以使用Apache Commons Compress库执行此操作。您可以从中下载1.2版本 http://mvnrepository.com/artifact/org.apache.commons/commons-compress/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;
}

59
2017-09-26 14:05



你的例子是一个很好的开始,但我似乎遇到了问题:while((entry =(TarArchiveEntry)debInputStream.getNextEntry())!= null)。问题是当我通过外部framewokr(例如SAXBuilder)处理第一个文件时,输入流debInputStream正在关闭,而第二次调用depInputStream.getNextEntry()会抛出异常“输入缓冲区被关闭” - adranale
相关,具有类似的实现: 如何使用Apache Commons解压缩TAR文件 - blong
感谢分享。如果他们在apache压缩库中放置一个unTar方法,本来会很好。似乎是一项基本操作。 - Andrew
当OutputStream outputFileStream = new FileOutputStream(outputFile)时,我遇到了'系统无法找到指定的路径'的问题;修复只需添加File parent = outputFile.getParentFile(); if(!parent.exists())parent.mkdirs(); - Georgy Gobozov
我想你需要这样做 is.close() - Slow Harry


Apache Commons VFS 支持tar作为 虚拟文件系统,支持像这样的URL tar:gz:HTTP:!//anyhost/dir/mytar.tar.gz /mytar.tar /path/in/tar/README.txt

TrueZip 或其继任者 TrueVFS 做同样的事情......它也可以从Maven Central获得。


11
2017-11-12 13:30





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

相关性:

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

9
2018-03-18 14:04





我刚尝试了一堆建议的libs(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>

6
2017-09-23 21:17





除了gzip和bzip2, Apache Commons Compress API 还有tar支持,最初基于 ICE工程Java焦油包,这是API和独立工具。


5
2017-11-12 13:19



Apache Commons Compress API有tar支持,最初基于ICE tar包,我相信: commons.apache.org/compress - Jörg
我的测试显示ICE焦油是五个竞争者中最快的(冰,压缩,蚂蚁,xeus + vfs),而Commons Compress排在第二位......但ICE tar似乎不那么可靠,WRT完整性解包所有条目和WRT保持归档条目原始文件名。 - Jörg


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


4
2017-11-24 21:55