На Java у нас есть Выходной поток ZipOutputStream
для создания zip-файла и GZIPOutputStream
для сжатия файла с помощью Gzip , но официального API для создания tar.gz
файл.
В Java мы можем использовать Apache Commons Сжатие (Все еще активно разрабатывается) для создания .tar.gz
файл.
org.apache.commons commons-compress 1.20
Записи
- tar предназначен для сбора файлов в один архивный файл, он же архив, и обычно имеет суффикс
.tar
- Gzip предназначен для сжатия файлов для экономии места и обычно имеет суффикс
.gz
- В
tar.gz
или.tgz
означает сгруппировать все файлы в один архивный файл и сжать его с помощью Gzip.
Приведенные ниже фрагменты кода создадут tar.gz
файл.
import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; //... try (OutputStream fOut = Files.newOutputStream(Paths.get("output.tar.gz")); BufferedOutputStream buffOut = new BufferedOutputStream(fOut); GzipCompressorOutputStream gzOut = new GzipCompressorOutputStream(buffOut); TarArchiveOutputStream tOut = new TarArchiveOutputStream(gzOut)) { TarArchiveEntry tarEntry = new TarArchiveEntry(file,fileName); tOut.putArchiveEntry(tarEntry); // copy file to TarArchiveOutputStream Files.copy(path, tOut); tOut.closeArchiveEntry(); tOut.finish(); }
Приведенные ниже фрагменты кода будут распаковывать .tar.gz
файл.
import org.apache.commons.compress.archivers.ArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; //... try (InputStream fi = Files.newInputStream(Paths.get("input.tar.gz")); BufferedInputStream bi = new BufferedInputStream(fi); GzipCompressorInputStream gzi = new GzipCompressorInputStream(bi); TarArchiveInputStream ti = new TarArchiveInputStream(gzi)) { ArchiveEntry entry; while ((entry = ti.getNextEntry()) != null) { // create a new path, remember check zip slip attack Path newPath = filename(entry, targetDir); //checking // copy TarArchiveInputStream to newPath Files.copy(ti, newPath); } }
1. Добавьте два файла в tar.gz
В этом примере показано, как добавить два файла в tar.gz
файл.
package com.mkyong.io.howto.compress; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import java.util.List; public class TarGzipExample1 { public static void main(String[] args) { try { Path path1 = Paths.get("/home/mkyong/test/sitemap.xml"); Path path2 = Paths.get("/home/mkyong/test/file.txt"); Path output = Paths.get("/home/mkyong/test/output.tar.gz"); Listpaths = Arrays.asList(path1, path2); createTarGzipFiles(paths, output); } catch (IOException e) { e.printStackTrace(); } System.out.println("Done"); } // tar.gz few files public static void createTarGzipFiles(List paths, Path output) throws IOException { try (OutputStream fOut = Files.newOutputStream(output); BufferedOutputStream buffOut = new BufferedOutputStream(fOut); GzipCompressorOutputStream gzOut = new GzipCompressorOutputStream(buffOut); TarArchiveOutputStream tOut = new TarArchiveOutputStream(gzOut)) { for (Path path : paths) { if (!Files.isRegularFile(path)) { throw new IOException("Support only file!"); } TarArchiveEntry tarEntry = new TarArchiveEntry( path.toFile(), path.getFileName().toString()); tOut.putArchiveEntry(tarEntry); // copy file to TarArchiveOutputStream Files.copy(path, tOut); tOut.closeArchiveEntry(); } tOut.finish(); } } }
Выход – Он добавляет Выход – Он добавляет
и
file.txt в один архивный файл
выведите.tar и сожмите его с помощью Gzip, и в результате получится
$ tar -tvf /home/mkyong/test/output.tar.gz -rw-r--r-- 0/0 396719 2020-08-12 14:02 sitemap.xml -rw-r--r-- 0/0 15 2020-08-11 17:56 file.txt
2. Добавьте каталог в tar.gz
В этом примере каталог, включая его вложенные файлы и подкаталоги, добавляется в один архивный файл, и Gzip сжимает его в .tar.gz
Идея состоит в том, чтобы использовать Files.walkFileTree
для обхода дерева файлов и добавления файла по одному в TarArchiveOutputStream
.
package com.mkyong.io.howto.compress; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; public class TarGzipExample2 { public static void main(String[] args) { try { // tar.gz a folder Path source = Paths.get("/home/mkyong/test"); createTarGzipFolder(source); } catch (IOException e) { e.printStackTrace(); } System.out.println("Done"); } // generate .tar.gz file at the current working directory // tar.gz a folder public static void createTarGzipFolder(Path source) throws IOException { if (!Files.isDirectory(source)) { throw new IOException("Please provide a directory."); } // get folder name as zip file name String tarFileName = source.getFileName().toString() + ".tar.gz"; try (OutputStream fOut = Files.newOutputStream(Paths.get(tarFileName)); BufferedOutputStream buffOut = new BufferedOutputStream(fOut); GzipCompressorOutputStream gzOut = new GzipCompressorOutputStream(buffOut); TarArchiveOutputStream tOut = new TarArchiveOutputStream(gzOut)) { Files.walkFileTree(source, new SimpleFileVisitor<>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) { // only copy files, no symbolic links if (attributes.isSymbolicLink()) { return FileVisitResult.CONTINUE; } // get filename Path targetFile = source.relativize(file); try { TarArchiveEntry tarEntry = new TarArchiveEntry( file.toFile(), targetFile.toString()); tOut.putArchiveEntry(tarEntry); Files.copy(file, tOut); tOut.closeArchiveEntry(); System.out.printf("file : %s%n", file); } catch (IOException e) { System.err.printf("Unable to tar.gz : %s%n%s%n", file, e); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) { System.err.printf("Unable to tar.gz : %s%n%s%n", file, exc); return FileVisitResult.CONTINUE; } }); tOut.finish(); } } }
3. Добавить строку в tar.gz
Этот пример добавляет Строка
в ByteArrayInputStream
и поместите ее в tararchiveoutputstream
напрямую. Это означает создать файл, не сохраняя его на локальном диске, и поместить файл в tar.gz
напрямую.
public static void createTarGzipFilesOnDemand() throws IOException { String data1 = "Test data 1"; String fileName1 = "111.txt"; String data2 = "Test data 2 3 4"; String fileName2 = "folder/222.txt"; String outputTarGzip = "/home/mkyong/output.tar.gz"; try (OutputStream fOut = Files.newOutputStream(Paths.get(outputTarGzip)); BufferedOutputStream buffOut = new BufferedOutputStream(fOut); GzipCompressorOutputStream gzOut = new GzipCompressorOutputStream(buffOut); TarArchiveOutputStream tOut = new TarArchiveOutputStream(gzOut)) { createTarArchiveEntry(fileName1, data1, tOut); createTarArchiveEntry(fileName2, data2, tOut); tOut.finish(); } } private static void createTarArchiveEntry(String fileName, String data, TarArchiveOutputStream tOut) throws IOException { byte[] dataInBytes = data.getBytes(); // create a byte[] input stream ByteArrayInputStream baOut1 = new ByteArrayInputStream(dataInBytes); TarArchiveEntry tarEntry = new TarArchiveEntry(fileName); // need defined the file size, else error tarEntry.setSize(dataInBytes.length); // tarEntry.setSize(baOut1.available()); alternative tOut.putArchiveEntry(tarEntry); // copy ByteArrayInputStream to TarArchiveOutputStream byte[] buffer = new byte[1024]; int len; while ((len = baOut1.read(buffer)) > 0) { tOut.write(buffer, 0, len); } tOut.closeArchiveEntry(); }
4. Распаковать файл – tar.gz
В этом примере показано, как распаковать и извлечь tar.gz
файл, и он также проверяет уязвимость zip-слипа .
package com.mkyong.io.howto.compress; import org.apache.commons.compress.archivers.ArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; public class TarGzipExample4 { public static void main(String[] args) { try { // decompress .tar.gz Path source = Paths.get("/home/mkyong/test/output.tar.gz"); Path target = Paths.get("/home/mkyong/test2"); decompressTarGzipFile(source, target); } catch (IOException e) { e.printStackTrace(); } System.out.println("Done"); } public static void decompressTarGzipFile(Path source, Path target) throws IOException { if (Files.notExists(source)) { throw new IOException("File doesn't exists!"); } try (InputStream fi = Files.newInputStream(source); BufferedInputStream bi = new BufferedInputStream(fi); GzipCompressorInputStream gzi = new GzipCompressorInputStream(bi); TarArchiveInputStream ti = new TarArchiveInputStream(gzi)) { ArchiveEntry entry; while ((entry = ti.getNextEntry()) != null) { // create a new path, zip slip validate Path newPath = zipSlipProtect(entry, target); if (entry.isDirectory()) { Files.createDirectories(newPath); } else { // check parent folder again Path parent = newPath.getParent(); if (parent != null) { if (Files.notExists(parent)) { Files.createDirectories(parent); } } // copy TarArchiveInputStream to Path newPath Files.copy(ti, newPath, StandardCopyOption.REPLACE_EXISTING); } } } } private static Path zipSlipProtect(ArchiveEntry entry, Path targetDir) throws IOException { Path targetDirResolved = targetDir.resolve(entry.getName()); // make sure normalized file still has targetDir as its prefix, // else throws exception Path normalizePath = targetDirResolved.normalize(); if (!normalizePath.startsWith(targetDir)) { throw new IOException("Bad entry: " + entry.getName()); } return normalizePath; } }
Дальнейшее чтение Пожалуйста, проверьте официальные Примеры сжатия Apache Commons/|.
Скачать Исходный Код
$клон git $клон git
$cd java-ввод-вывод
Рекомендации
- Википедия – тар
- Gzip
- Общие ресурсы Apache Сжимаются
- Java – Создайте zip-файл
- Java – Сжатие файла в Gzip
- уязвимость проскальзывания молнии
Оригинал: “https://mkyong.com/java/how-to-create-tar-gz-in-java/”