Автор оригинала: 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/”