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

log4j2.xml Как распаковать zip-файл на Java

В этом примере показано, как распаковать zip-файл на Java, используя `ZipInputStream` и zip4j, чтобы защитить уязвимость проскальзывания zip.

Автор оригинала: mkyong.

В этой статье показано, как использовать ZipInputStream и zip4j библиотека для распаковки zip-файла на Java.

Чтобы распаковать файл вручную, не забудьте добавить проверку на уязвимость zip slip .

  Path targetDirResolved = targetDir.resolve(zipEntry.getName());

  // make sure normalized file still has targetDir as its prefix
  Path normalizePath = targetDirResolved.normalize();

  if (!normalizePath.startsWith(targetDir)) {
      // may be zip slip, better stop and throws exception
      throw new IOException("Bad zip entry: " + zipEntry.getName());
  }

1. Zip-Файл

В этой статье создана следующая структура zip – файла – создайте zip – файл на Java . Позже мы покажем, как распаковать его в новую папку.

1.1 Zip-файл содержит только файлы.

$ unzip -l test.zip

Archive:  test.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2020-08-06 18:49   test-a2.log
        0  2020-08-06 18:49   test-a1.log
       14  2020-08-06 18:49   data/db.debug.conf
       42  2020-08-06 18:49   README.md
       32  2020-08-06 18:49   Test.java
        0  2020-08-06 18:49   test-b/test-b1.txt
        0  2020-08-06 18:49   test-b/test-c/test-c2.log
        0  2020-08-06 18:49   test-b/test-c/test-c1.log
        0  2020-08-06 18:49   test-b/test-b2.txt
        0  2020-08-06 18:49   test-b/test-d/test-d2.log
        0  2020-08-06 18:49   test-b/test-d/test-d1.log
---------                     -------
       88                     11 files

1.2 Zip-файл содержит папки и файлы.

$ unzip -l test.zip

Archive:  test.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2020-07-27 15:10   test-a2.log
        0  2020-07-23 14:55   test-a1.log
        0  2020-08-06 18:57   data/
       14  2020-08-04 14:07   data/db.debug.conf
       42  2020-08-05 19:04   README.md
       32  2020-08-05 19:04   Test.java
        0  2020-08-06 18:57   test-b/
        0  2020-07-24 15:49   test-b/test-b1.txt
        0  2020-08-06 18:57   test-b/test-c/
        0  2020-07-27 15:11   test-b/test-c/test-c2.log
        0  2020-07-27 15:11   test-b/test-c/test-c1.log
        0  2020-07-27 15:10   test-b/test-b2.txt
        0  2020-08-06 18:57   test-b/test-d/
        0  2020-07-27 15:11   test-b/test-d/test-d2.log
        0  2020-07-27 15:11   test-b/test-d/test-d1.log
---------                     -------
       88                     15 files

2. Распаковать файл – ZipInputStream

Чтобы распаковать zip-файл, мы используем ZipInputStream для чтения zip-файла и копирования файлов из zip-файла в новую папку (вне zip-файла).

Ниже приведен пример распаковки zip-файла /home/mkyong/zip/test.zip в папку /главная/mkyong/почтовый индекс/ , также обеспечивает проверку для предотвращения уязвимости zip-проскальзывания |/.

package com.mkyong.io.howto;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class ZipFileUnZipExample {

    public static void main(String[] args) {

        Path source = Paths.get("/home/mkyong/zip/test.zip");
        Path target = Paths.get("/home/mkyong/zip/");

        try {

            unzipFolder(source, target);
            System.out.println("Done");

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void unzipFolder(Path source, Path target) throws IOException {

        try (ZipInputStream zis = new ZipInputStream(new FileInputStream(source.toFile()))) {

            // list files in zip
            ZipEntry zipEntry = zis.getNextEntry();

            while (zipEntry != null) {

                boolean isDirectory = false;
                // example 1.1
                // some zip stored files and folders separately
                // e.g data/
                //     data/folder/
                //     data/folder/file.txt
                if (zipEntry.getName().endsWith(File.separator)) {
                    isDirectory = true;
                }

                Path newPath = zipSlipProtect(zipEntry, target);

                if (isDirectory) {
                    Files.createDirectories(newPath);
                } else {

                    // example 1.2
                    // some zip stored file path only, need create parent directories
                    // e.g data/folder/file.txt
                    if (newPath.getParent() != null) {
                        if (Files.notExists(newPath.getParent())) {
                            Files.createDirectories(newPath.getParent());
                        }
                    }

                    // copy files, nio
                    Files.copy(zis, newPath, StandardCopyOption.REPLACE_EXISTING);

                    // copy files, classic
                    /*try (FileOutputStream fos = new FileOutputStream(newPath.toFile())) {
                        byte[] buffer = new byte[1024];
                        int len;
                        while ((len = zis.read(buffer)) > 0) {
                            fos.write(buffer, 0, len);
                        }
                    }*/
                }

                zipEntry = zis.getNextEntry();

            }
            zis.closeEntry();

        }

    }

    // protect zip slip attack
    public static Path zipSlipProtect(ZipEntry zipEntry, Path targetDir)
        throws IOException {

        // test zip slip vulnerability
        // Path targetDirResolved = targetDir.resolve("../../" + zipEntry.getName());

        Path targetDirResolved = targetDir.resolve(zipEntry.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 zip entry: " + zipEntry.getName());
        }

        return normalizePath;
    }

}

Выход

$ pwd
/home/mkyong/zip/

$ tree
.
├── data
│   └── db.debug.conf
├── README.md
├── test-a1.log
├── test-a2.log
├── test-b
│   ├── test-b1.txt
│   ├── test-b2.txt
│   ├── test-c
│   │   ├── test-c1.log
│   │   └── test-c2.log
│   └── test-d
│       ├── test-d1.log
│       └── test-d2.log
├── Test.java

3. Распаковать файл – zip4j

В этом примере используется библиотека zip4j для распаковки zip-файла.

  
      net.lingala.zip4j
      zip4j
      2.6.1
  
  // it takes `File` as arguments
  public static void unzipFolderZip4j(Path source, Path target)
        throws IOException {

        new ZipFile(source.toFile())
                .extractAll(target.toString());

  }

4. Исключение ZipException: недопустимый размер записи

Если мы попадем в следующее исключение недопустимый размер записи , это означает, что zip-файл поврежден в процессе копирования, передачи или создания. Невозможно исправить поврежденный размер файла, снова получить новый zip-файл.

java.util.zip.ZipException: invalid entry size (expected 0 but got 1282 bytes)
	at java.base/java.util.zip.ZipInputStream.readEnd(ZipInputStream.java:398)
	at java.base/java.util.zip.ZipInputStream.read(ZipInputStream.java:197)
	at java.base/java.io.FilterInputStream.read(FilterInputStream.java:107)
	at com.mkyong.io.howto.ZipFileUnZipExample.unzipFolder(ZipFileUnZipExample.java:63)
	at com.mkyong.io.howto.ZipFileUnZipExample.main(ZipFileUnZipExample.java:22)

Скачать Исходный Код

$ клон git $ клон git

$ $ cd java-ввод-вывод/как

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

Оригинал: “https://mkyong.com/java/how-to-decompress-files-from-a-zip-file/”