【问题标题】:How do I extract a tar file in Java?如何在 Java 中提取 tar 文件?
【发布时间】:2010-09-23 20:34:20
【问题描述】:

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

【问题讨论】:

  • skiphoppy,在我最初回答的 2008 年之后,Apache Commons Compress 项目发布了。您可能应该接受this answer 以便更突出显示它。

标签: java archive tar


【解决方案1】:

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

这里有两种方法:一种是解压缩文件,另一种是解压缩文件。所以,对于一个文件 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;
}

【讨论】:

  • 你的例子是一个很好的开始,但我似乎有一个问题:while ((entry = (TarArchiveEntry)debInputStream.getNextEntry()) != null)。问题是当我通过外部 framewokr(例如 SAXBuilder)处理第一个文件时,输入流 debInputStream 正在关闭,第二次调用 depInputStream.getNextEntry() 抛出异常“输入缓冲区已关闭”
  • 感谢分享。如果他们在 apache compress 库中放置一个 unTar 方法会很好。似乎是一项基本操作。
  • 当 OutputStream outputFileStream = new FileOutputStream(outputFile); 时,我遇到了“系统找不到指定的路径”的问题;修复只需添加 File parent = outputFile.getParentFile(); if (!parent.exists()) parent.mkdirs();
  • 警告!上面的代码有一个安全漏洞(zip 文件可能包含一个相对路径,这将导致目标目录之外的文件被覆盖)。请参阅snyk.io/research/… 了解如何修复它。
【解决方案2】:

注意:此功能后来通过单独的项目 Apache Commons Compress 发布,名称为 described in another answer. 此答案已过时。


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

Gzip is part of Java SE(我猜 Ant 实现遵循相同的模型)。

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

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

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

【讨论】:

  • 我正要告诉他有关 GZIPInputStream 的事。但这对他没有帮助,因为他仍然需要阅读包含的 .tar 文件:)
  • 事实是我已经知道 GZIPInputStream,这要感谢我在这里提出的另一个问题。但我对 tar API 一无所知,我希望可能有一些东西可以以集成方式处理 gzip,所以我不想通过说出我已经知道的一切来限制答案。
  • 'ant' 中捆绑的 Apache 类工作正常。我每天都使用这个:org.apache.tools.tar.TarEntry 和 org.apache.tools.tar.TarInputStream;该代码与您用于解压缩 zip 文件的代码非常相似。如果你想做 Bzip2,请使用 jaxlib。
  • 这里有(奇怪的是)Ant / TarInputStream 种类的一个很好的例子。 code.google.com/p/jtar +1 使用 ant 库顺便说一句
【解决方案3】:
Archiver archiver = ArchiverFactory.createArchiver("tar", "gz");
archiver.extract(archiveFile, destDir);

依赖:

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

【讨论】:

    【解决方案4】:

    Apache Commons VFS 支持 tar 作为一种虚拟文件系统,它支持像 tar:gz:@987654322@ 这样的 URL

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

    【讨论】:

      【解决方案5】:

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

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

        【讨论】:

        • Apache Commons Compress API 支持 tar 并且最初基于上面的 ICE tar 包我相信:commons.apache.org/compress
        • 我的测试显示 ICE tar 在五个竞争者(ice、compress、ant、xeus + vfs)中是最快的,而 Commons Compress 排在第二位……但是 ICE tar 似乎不太可靠 WRT解压所有条目的完整性,并 WRT 保留存档条目的原始文件名。
        【解决方案7】:

        API 用于 tar 文件,将 other one 包含在 Ant 中的 BZIP2 和 standard one 用于 GZIP 怎么样?

        【讨论】:

          【解决方案8】:

          这是一个基于 Dan Borza 的 this earlier answer 的版本,它使用 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();
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-11-13
            • 2017-09-23
            相关资源
            最近更新 更多