Рубрики
Без рубрики

Как создать tar.gz на Яве

В этой статье показано, как создать `tar.gz `файл на Java, с использованием библиотеки Apache `commons-compress`.

На Java у нас есть Выходной поток ZipOutputStream для создания zip-файла и GZIPOutputStream для сжатия файла с помощью Gzip , но официального API для создания tar.gz файл.

В Java мы можем использовать Apache Commons Сжатие (Все еще активно разрабатывается) для создания .tar.gz файл.

  
      org.apache.commons
      commons-compress
      1.20
  

Записи

  1. tar предназначен для сбора файлов в один архивный файл, он же архив, и обычно имеет суффикс .tar
  2. Gzip предназначен для сжатия файлов для экономии места и обычно имеет суффикс .gz
  3. В 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");

            List paths = 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-ввод-вывод

Рекомендации

Оригинал: “https://mkyong.com/java/how-to-create-tar-gz-in-java/”