Como faço para extrair um arquivo tar em Java?
Pergunta
Como faço para extrair um tar (ou tar.gz ou tar.bz2) arquivo em Java?
Solução
Nota: Esta funcionalidade foi publicado mais tarde através de um projeto separado, Apache Commons Compress, como descrito em outro resposta. Esta resposta está fora de data.
Eu não usei um tar API diretamente, mas alcatrão e bzip2 são implementados em Ant; você poderia pedir a sua execução, ou, eventualmente, usar Ant para fazer o que você precisa.
Gzip faz parte de Java SE (e eu estou supondo que a implementação Ant segue o mesmo modelo).
GZIPInputStream
é apenas um decorador InputStream
. Você pode envolver, por exemplo, um FileInputStream
em um GZIPInputStream
e usá-lo da mesma forma que você usaria qualquer InputStream
:
InputStream is = new GZIPInputStream(new FileInputStream(file));
(Note que o GZIPInputStream tem seu próprio buffer, interna, de modo envolvendo a FileInputStream
em um BufferedInputStream
provavelmente diminuir o desempenho.)
Outras dicas
Você pode fazer isso com a biblioteca Apache Commons Compress. Você pode baixar a versão 1.2 de http://mvnrepository.com/artifact/ org.apache.commons / comuns-compressa / 1,2 .
Aqui estão dois métodos: um que descompacta um arquivo e um outro que untars-lo. Assim, para um arquivo
Aproveite.
/** 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 VFS suportes tar como um sistema de arquivos virtual , que suporta URLs como este tar:gz:http://anyhost/dir/mytar.tar.gz!/mytar.tar!/path/in/tar/README.txt
TrueZip ou seu sucessor TrueVFS faz o mesmo ... também é disponível a partir Maven Central.
Archiver archiver = ArchiverFactory.createArchiver("tar", "gz");
archiver.extract(archiveFile, destDir);
Dependência:
<dependency>
<groupId>org.rauschig</groupId>
<artifactId>jarchivelib</artifactId>
<version>0.5.0</version>
</dependency>
Eu apenas tentei um monte das libs sugeridas (TrueZip, Apache Compress), mas sem sorte.
Aqui está um exemplo com 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();
}
}
E a dependência Maven:
<dependency>
<groupId>commons-vfs</groupId>
<artifactId>commons-vfs</artifactId>
<version>1.0</version>
</dependency>
Além de gzip e bzip2, Apache Commons Compress API também tem suporte alcatrão, originalmente baseada em ICE Engenharia Java Tar Package, que é tanto ferramenta API e independente.
Aqui está uma versão com base em esta resposta anteriormente por Dan Borza que usos Apache Commons Compress e Java NIO (ie caminho em vez de Arquivo). Ele também faz a descompactação e untarring em um fluxo por isso não há criação de arquivo intermediário.
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();
}