Автор оригинала: 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-ввод-вывод/как
Рекомендации
- Википедия – Zip
- Создайте Zip-файл на Java
- Произвольная запись файла во время извлечения архива (“Промах Zip”)
- библиотека zip4j
- Поставщик Файловой системы Zip
- Спецификация формата ZIP-файла
- ZipInputStream javadoc в формате ZipInputStream
Оригинал: “https://mkyong.com/java/how-to-decompress-files-from-a-zip-file/”