【发布时间】:2010-09-23 20:34:20
【问题描述】:
如何在 Java 中提取 tar(或 tar.gz 或 tar.bz2)文件?
【问题讨论】:
-
skiphoppy,在我最初回答的 2008 年之后,Apache Commons Compress 项目发布了。您可能应该接受this answer 以便更突出显示它。
如何在 Java 中提取 tar(或 tar.gz 或 tar.bz2)文件?
【问题讨论】:
您可以使用 Apache Commons Compress 库来执行此操作。您可以从http://mvnrepository.com/artifact/org.apache.commons/commons-compress/1.2 下载 1.2 版本。
这里有两种方法:一种是解压缩文件,另一种是解压缩文件。所以,对于一个文件
享受吧。
/** 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;
}
【讨论】:
注意:此功能后来通过单独的项目 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 中可能会降低性能。)
【讨论】:
Archiver archiver = ArchiverFactory.createArchiver("tar", "gz");
archiver.extract(archiveFile, destDir);
依赖:
<dependency>
<groupId>org.rauschig</groupId>
<artifactId>jarchivelib</artifactId>
<version>0.5.0</version>
</dependency>
【讨论】:
Apache Commons VFS 支持 tar 作为一种虚拟文件系统,它支持像 tar:gz:@987654322@ 这样的 URL
【讨论】:
我刚刚尝试了一堆建议的库(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>
【讨论】:
除了 gzip 和 bzip2,Apache Commons Compress API 还支持 tar,最初基于 ICE Engineering Java Tar Package,它既是 API 又是独立工具。
【讨论】:
将API 用于 tar 文件,将 other one 包含在 Ant 中的 BZIP2 和 standard one 用于 GZIP 怎么样?
【讨论】:
这是一个基于 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();
}
【讨论】: