Пример кода Java для распаковки и извлечения файлов из сжатого zip-файла с использованием пакета java.util.zip.
В примере открывается zip-файл и начинается обход файлов, аналогичный обходу дерева каталогов. Если мы находим запись каталога, мы создаем новый каталог. Если мы находим запись файла, мы записываем распакованный файл.
См. также: Создание защищенного паролем ZIP-архива с помощью Zip4J
1. Распакуйте файл с помощью java.util.zip.ZipFile
В примере используется ZipInputStream для чтения ZipFile, а затем по одному считываются все ZipEntry. Затем используется FileOutputStream для записи всех файлов в файловую систему.
Следующий пример делает следующее:
- Он создает новую папку, в которую будут скопированы несжатые файлы. Имя папки берется из имени zip-файла без расширения. Например, если мы распакуем файл data.zip, то он будет извлечен в папку data в том же месте. Объект ZipFile представляет .zip-файл и используется для доступа к его информации.
- Программа перебирает все файлы в zip-архиве и проверяет, является ли он каталогом или файлом. Класс ZipEntry представляет запись в zip-архиве — файл или каталог. Каждый экземпляр ZipEntry имеет информацию о сжатом и несжатом размере, имя и входной поток несжатых байтов.
- Если ZipEntry — это каталог, то создайте новый каталог внутри целевого каталога data; в противном случае извлеките файл в указанное место.
- Используя Files.copy(), мы считываем несжатый файл из zip-архива и копируем его в целевой каталог.
- Продолжайте делать это, пока весь файл не будет обработан.
import java.io.*;import java.nio.file.FileSystem;import java.nio.file.FileSystems;import java.nio.file.Files;import java.nio.file.Path;import java.util.Enumeration;import java.util.zip.ZipEntry;import java.util.zip.ZipFile;import org.apache.commons.io.FilenameUtils;public class UnzipExample{public static void main(String[] args){Path zipFile = Path.of("c:/temp/data.zip");unzipFile(zipFile);}private static void unzipFile(Path filePathToUnzip) {Path parentDir = filePathToUnzip.getParent();String fileName = filePathToUnzip.toFile().getName();Path targetDir = parentDir.resolve(FilenameUtils.removeExtension(fileName));//Open the filetry(ZipFile zip = new ZipFile(filePathToUnzip.toFile())) {FileSystem fileSystem = FileSystems.getDefault();Enumeration<? extends ZipEntry> entries = zip.entries();//We will unzip files in this folderif(!targetDir.toFile().isDirectory()&& !targetDir.toFile().mkdirs()) {throw new IOException("failed to create directory " + targetDir);}//Iterate over entrieswhile(entries.hasMoreElements()) {ZipEntry entry = entries.nextElement();File f = new File(targetDir.resolve(Path.of(entry.getName())).toString());//If directory then create a new directory in uncompressed folderif(entry.isDirectory()) {if(!f.isDirectory() && !f.mkdirs()) {throw new IOException("failed to create directory " + f);}}//Else create the fileelse {File parent = f.getParentFile();if(!parent.isDirectory() && !parent.mkdirs()) {throw new IOException("failed to create directory " + parent);}try(InputStream in = zip.getInputStream(entry)) {Files.copy(in, f.toPath());}}}} catch(IOException e) {e.printStackTrace();}}}
2. Распакуйте файл с помощью Apache Commons Compress
Общие шаги по распаковке файла с использованием библиотеки commons-compress аналогичны описанным в первом разделе. Отличаются только имена классов, за исключением очень немногих незначительных отличий.
Начните с импорта последней версии commons-compress из репозитория maven.
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-compress</artifactId><version>1.21</version></dependency>
Далее мы перепишем логику с использованием API сжатия. Основные изменения — это новые классы ArchiveEntry и ArchiveStreamFactory и ArchiveInputStream.
- Экземпляры ArchiveEntry предоставляют метаданные об отдельных записях архива.
- ArchiveInputStream помогает в чтении различных форматов zip-файлов, таких как .zip, .zip.gz или tar-файл .tar.gz. Например, для чтения tar-файла мы можем создать экземпляр TarArchiveInputStream следующим образом.
try(InputStream fi = Files.newInputStream(Paths.get("my.tar.gz"));InputStream bi = new BufferedInputStream(fi);InputStream gzi = new GzipCompressorInputStream(bi);ArchiveInputStream o = new TarArchiveInputStream(gzi)) {}
Давайте создадим простую программу, похожую на первую, которая извлечет заданный сжатый файл в тот же каталог.
import org.apache.commons.compress.archivers.ArchiveEntry;import org.apache.commons.compress.archivers.ArchiveException;import org.apache.commons.compress.archivers.ArchiveInputStream;import org.apache.commons.compress.archivers.ArchiveStreamFactory;import org.apache.commons.compress.utils.IOUtils;import org.apache.commons.io.FilenameUtils;import java.io.*;import java.nio.file.Files;import java.nio.file.Path;import java.nio.file.Paths;public class UnzipWithCommonCompress {public static void main(String[] args) throws IOException, ArchiveException {Path zipFile = Path.of("c:/temp/data.zip");extractZip(zipFile);}private static void extractZip(Path zipFilePath) {Path parentDir = zipFilePath.getParent();String fileName = zipFilePath.toFile().getName();Path targetDir = parentDir.resolve(FilenameUtils.removeExtension(fileName));ArchiveStreamFactory archiveStreamFactory = new ArchiveStreamFactory();try(InputStream inputStream = Files.newInputStream(zipFilePath);ArchiveInputStream archiveInputStream = archiveStreamFactory.createArchiveInputStream(ArchiveStreamFactory.ZIP, inputStream)) {ArchiveEntry archiveEntry = null;while((archiveEntry = archiveInputStream.getNextEntry()) != null) {Path path = Paths.get(targetDir.toString(), archiveEntry.getName());File file = path.toFile();if(archiveEntry.isDirectory()) {if(!file.isDirectory()) {file.mkdirs();}} else {File parent = file.getParentFile();if(!parent.isDirectory()) {parent.mkdirs();}try(OutputStream outputStream = Files.newOutputStream(path)) {IOUtils.copy(archiveInputStream, outputStream);}}}} catch(IOException e) {throw new RuntimeException(e);} catch(ArchiveException e) {throw new RuntimeException(e);}}}