- Zip file for java
- ZipOutputStream. Запись архивов
- Чтение архивов. ZipInputStream
- Rukovodstvo
- статьи и идеи для разработчиков программного обеспечения и веб-разработчиков.
- Работа с Zip-файлами в Java
- Введение В этой статье я расскажу об основах создания, взаимодействия, проверки и извлечения файлов zip-архива с помощью Java (в частности, OpenJDK 11). Пример кода, используемый в этой статье, имеет форму проекта Gradle и размещен в этом репозитории GitHub [https://github.com/amcquistan/zip-files-in-java], чтобы вы могли запускать и экспериментировать. Будьте осторожны при изменении кода, удаляющего файлы. Как уже упоминалось, приведенные здесь примеры кода написаны с использованием Java 11 и util
- Вступление
- Ключевые классы Java для работы с Zip-архивами
- Общие пути к файлам для примеров кода
- Проверка содержимого Zip-архива
- Извлечение Zip-архива
- Запись файлов непосредственно в новый Zip-архив
- Архивирование существующего файла в новый Zip-архив
- Архивирование папки в новый ZIP-архив
- Заключение
- Class ZipFile
- Field Summary
- Constructor Summary
- Method Summary
- Methods declared in class java.lang.Object
- Field Details
- OPEN_READ
- OPEN_DELETE
- LOCSIG
- EXTSIG
- CENSIG
- ENDSIG
- LOCHDR
- EXTHDR
- CENHDR
- ENDHDR
- LOCVER
- LOCFLG
- LOCHOW
- LOCTIM
- LOCCRC
- LOCSIZ
- LOCLEN
- LOCNAM
- LOCEXT
- EXTCRC
- EXTSIZ
- EXTLEN
- CENVEM
- CENVER
- CENFLG
- CENHOW
- CENTIM
- CENCRC
- CENSIZ
- CENLEN
- CENNAM
- CENEXT
- CENCOM
- CENDSK
- CENATT
- CENATX
- CENOFF
- ENDSUB
- ENDTOT
- ENDSIZ
- ENDOFF
- ENDCOM
- Constructor Details
- ZipFile
- ZipFile
- ZipFile
- ZipFile
- ZipFile
- ZipFile
- Method Details
- getComment
- getEntry
- getInputStream
- getName
- entries
- stream
- size
- close
Zip file for java
Кроме общего функционала для работы с файлами Java предоставляет функциональность для работы с таким видом файлов как zip-архивы. Для этого в пакете java.util.zip определены два класса — ZipInputStream и ZipOutputStream
ZipOutputStream. Запись архивов
Для создания архива используется класс ZipOutputStream. Для создания объекта ZipOutputStream в его конструктор передается поток вывода:
ZipOutputStream(OutputStream out)
Для записи файлов в архив для каждого файла создается объект ZipEntry , в конструктор которого передается имя архивируемого файла. А чтобы добавить каждый объект ZipEntry в архив, применяется метод putNextEntry() .
import java.io.*; import java.util.zip.*; public class Program < public static void main(String[] args) < String filename = "notes.txt"; try(ZipOutputStream zout = new ZipOutputStream(new FileOutputStream("output.zip")); FileInputStream fis= new FileInputStream(filename);) < ZipEntry entry1=new ZipEntry("notes.txt"); zout.putNextEntry(entry1); // считываем содержимое файла в массив byte byte[] buffer = new byte[fis.available()]; fis.read(buffer); // добавляем содержимое к архиву zout.write(buffer); // закрываем текущую запись для новой записи zout.closeEntry(); >catch(Exception ex) < System.out.println(ex.getMessage()); >> >
После добавления объекта ZipEntry в поток нам также надо добавить в него и содержимое файла. Для этого используется метод write, записывающий в поток массив байтов: zout.write(buffer); . В конце надо закрыть ZipEntry с помощью метода closeEntry() . После этого можно добавлять в архив новые файлы — в этом случае все вышеописанные действия для каждого нового файла повторяются.
Чтение архивов. ZipInputStream
Для чтения архивов применяется класс ZipInputStream . В конструкторе он принимает поток, указывающий на zip-архив:
ZipInputStream(InputStream in)
Для считывания файлов из архива ZipInputStream использует метод getNextEntry() , который возвращает объект ZipEntry . Объект ZipEntry представляет отдельную запись в zip-архиве. Например, считаем какой-нибудь архив:
import java.io.*; import java.util.zip.*; public class Program < public static void main(String[] args) < try(ZipInputStream zin = new ZipInputStream(new FileInputStream("output.zip"))) < ZipEntry entry; String name; while((entry=zin.getNextEntry())!=null)< name = entry.getName(); // получим название файла System.out.printf("File name: %s \n", name); // распаковка FileOutputStream fout = new FileOutputStream("new" + name); for (int c = zin.read(); c != -1; c = zin.read()) < fout.write(c); >fout.flush(); zin.closeEntry(); fout.close(); > > catch(Exception ex) < System.out.println(ex.getMessage()); >> >
ZipInputStream в конструкторе получает ссылку на поток ввода. И затем в цикле выводятся все файлы и их размер в байтах, которые находятся в данном архиве.
Затем данные извлекаются из архива и сохраняются в новые файлы, которые находятся в той же папке и которые начинаются с «new».
Rukovodstvo
статьи и идеи для разработчиков программного обеспечения и веб-разработчиков.
Работа с Zip-файлами в Java
Введение В этой статье я расскажу об основах создания, взаимодействия, проверки и извлечения файлов zip-архива с помощью Java (в частности, OpenJDK 11). Пример кода, используемый в этой статье, имеет форму проекта Gradle и размещен в этом репозитории GitHub [https://github.com/amcquistan/zip-files-in-java], чтобы вы могли запускать и экспериментировать. Будьте осторожны при изменении кода, удаляющего файлы. Как уже упоминалось, приведенные здесь примеры кода написаны с использованием Java 11 и util
Вступление
В этой статье я расскажу об основах создания, взаимодействия, проверки и извлечения файлов zip-архива с помощью Java (в частности, OpenJDK 11). Образец кода, используемый в этой статье, представляет собой проект Gradle и размещен в этом репозитории GitHub, чтобы вы могли запускать и экспериментировать. Будьте осторожны при изменении кода, удаляющего файлы.
Как уже упоминалось, приведенные здесь примеры кода написаны с использованием Java 11 и используют var которое было введено в Java 10, и парадигмы функционального программирования в Java 8, поэтому для их запуска требуется минимальная версия Java 10.
Ключевые классы Java для работы с Zip-архивами
Я считаю, что неплохо начать с определения некоторых известных классов, которые обычно используются при работе с zip-архивами в Java. Эти классы java.nio.file пакетах java.util.zip или java.nio.file.
- java.util.zip.ZipFile используется для чтения и взаимодействия с элементами ( ZipEntry ) в zip-архиве
- java.util.zip.ZipEntry — это абстракция, представляющая такой элемент, как файл или каталог в zip-архиве (т. е. экземпляр ZipFile
- java.util.zip.ZipOutputStream — это реализация абстрактного класса OutputStream, который используется для записи элементов в Zip-файл.
- java.nio.file.Files — очень удобный класс утилит для потоковой передачи и копирования файловых данных в экземпляры ZipOutputStream или из экземпляров ZipFile.
- java.nio.file.Path — еще один удобный класс утилит для эффективной работы с путями к файлам
Общие пути к файлам для примеров кода
В примере кода я использую два общих каталога для записи и чтения данных в / из которых оба относятся к корню проекта Gradle. Взгляните на связанный репо во введении или, что еще лучше, запустите образцы. Просто помните об этих двух переменных Path, поскольку они часто используются в качестве начального каталога для входов и выходов.
Проверка содержимого Zip-архива
Вы можете создать экземпляр ZipFile и передать ему путь к существующему zip-архиву, который, по сути, открывает его, как любой другой файл, а затем проверяет содержимое, запрашивая ZipEntry содержащееся внутри него. Обратите внимание на то, что ZipFile реализует интерфейс AutoCloseable , что делает его отличным кандидатом на конструкцию программирования Java «попытка с ресурсами», показанную ниже и во всех приведенных здесь примерах.
static void showZipContents() < try (var zf = new ZipFile("ZipToInspect.zip")) < System.out.println(String.format("Inspecting contents of: %s\n", zf.getName())); EnumerationzipEntries = zf.entries(); zipEntries.asIterator().forEachRemaining(entry -> < System.out.println(String.format( "Item: %s \nType: %s \nSize: %d\n", entry.getName(), entry.isDirectory() ? "directory" : "file", entry.getSize() )); >); > catch (IOException e) < e.printStackTrace(); >>
Запуск проекта Gradle с использованием следующего:
Это дает результат для метода App.showZipContents
> Task :run Inspecting contents of: ZipToInspect.zip Item: ZipToInspect/ Type: directory Size: 0 Item: ZipToInspect/greetings.txt Type: file Size: 160 Item: ZipToInspect/InnerFolder/ Type: directory Size: 0 Item: ZipToInspect/InnerFolder/About.txt Type: file Size: 39
Здесь вы можете видеть, что это распечатывает все файлы и каталоги в zip-архиве, даже файлы в каталогах.
Извлечение Zip-архива
Извлечение содержимого zip-архива на диск не требует ничего, кроме репликации той же структуры каталогов, что и внутри ZipFile , которую можно определить с помощью ZipEntry.isDirectory а затем копирования файлов, представленных в ZipEntry на диск.
static void unzipAZip() < var outputPath = Path.of("UnzippedContents"); try (var zf = new ZipFile("ZipToInspect.zip")) < // Delete if exists, then create a fresh empty directory to put the zip archive contents initialize(outputPath); EnumerationzipEntries = zf.entries(); zipEntries.asIterator().forEachRemaining(entry -> < try < if (entry.isDirectory()) < var dirToCreate = outputPath.resolve(entry.getName()); Files.createDirectories(dirToCreate); >else < var fileToCreate = outputPath.resolve(entry.getName()); Files.copy(zf.getInputStream(entry), fileToCreate); >> catch(IOException ei) < ei.printStackTrace(); >>); > catch(IOException e) < e.printStackTrace(); >>
Запись файлов непосредственно в новый Zip-архив
Поскольку запись zip-архива на самом деле является не чем иным, как записью потока данных в какое-то место назначения (в данном случае Zip-файл), запись данных, таких как String, в zip-архив, отличается только тем, что вам нужно сопоставить данные, которые записано в ZipEntry добавленные в ZipOutputStream .
Опять же, ZipOutputStream реализует AutoCloseable , поэтому его лучше всего использовать с оператором try-with-resources. Единственная реальная проблема — не забыть закрыть свой ZipEntry когда вы закончите с каждым из них, чтобы было ясно, когда он больше не должен получать данные.
static void zipSomeStrings() < MapstringsToZip = Map.ofEntries( entry("file1", "This is the first file"), entry("file2", "This is the second file"), entry("file3", "This is the third file") ); var zipPath = zippedDir.resolve("ZipOfStringData.zip"); try (var zos = new ZipOutputStream( new BufferedOutputStream(Files.newOutputStream(zipPath)))) < for (var entry : stringsToZip.entrySet()) < zos.putNextEntry(new ZipEntry(entry.getKey())); zos.write(entry.getValue().getBytes()); zos.closeEntry(); >> catch (IOException e) < e.printStackTrace(); >>
Архивирование существующего файла в новый Zip-архив
Если вы ранее копировали файл на Java, то вы уже являетесь ПРОФЕССИОНАЛОМ в создании zip-архива из существующего файла (или каталога, если на то пошло). Опять же, единственное реальное отличие состоит в том, что вам нужно проявить дополнительную осторожность, чтобы убедиться, что вы сопоставляете файлы с соответствующими экземплярами ZipEntry
В этом примере я создаю входной файл «FileToZip.txt» и записываю в него данные «Привет, друзья Java!» а затем используйте Files.copy (Path, OutputStream), чтобы связать ZipEntry с файлом FileToZip.txt внутри zip-архива ZippedFile.zip, который я создаю с экземпляром ZipOutoutStream
static void zipAFile() < var inputPath = inputDataDir.resolve("FileToZip.txt"); var zipPath = zippedDir.resolve("ZippedFile.zip"); try (var zos = new ZipOutputStream( new BufferedOutputStream(Files.newOutputStream(zipPath)))) < Files.writeString(inputPath, "Howdy There Java Friends!\n"); zos.putNextEntry(new ZipEntry(inputPath.toString())); Files.copy(inputPath, zos); zos.closeEntry(); >catch (IOException e) < e.printStackTrace(); >>
Архивирование папки в новый ZIP-архив
Архивирование непустого каталога становится немного сложнее, особенно если вы хотите сохранить пустые каталоги в родительском каталоге. Чтобы поддерживать наличие пустого каталога в zip-архиве, вам необходимо обязательно создать запись с суффиксом разделителя каталогов файловой системы при создании ее ZipEntry , а затем немедленно закрыть ее.
В этом примере я создаю каталог с именем «foldertozip», содержащий структуру, показанную ниже, а затем заархивирую его в zip-архив.
tree . . └── foldertozip ├── emptydir ├── file1.txt └── file2.txt
В следующем коде обратите внимание на то, что я использую метод Files.walk(Path) для обхода дерева каталогов «foldertozip» и поиска пустых каталогов («emptydir» в этом примере), и если / когда обнаружен, я присоединяю разделитель каталогов к имя в ZipEntry . После этого я закрываю его, как только добавляю в экземпляр ZipOutputStream
Я также использую несколько иной подход к внедрению файлов, не являющихся каталогами, в ZipOutputStream по сравнению с предыдущим примером, но я просто использую этот другой подход для разнообразия примеров.
static void zipADirectoryWithFiles() < var foldertozip = inputDataDir.resolve("foldertozip"); var dirFile1 = foldertozip.resolve("file1.txt"); var dirFile2 = foldertozip.resolve("file2.txt"); var zipPath = zippedDir.resolve("ZippedDirectory.zip"); try (var zos = new ZipOutputStream( new BufferedOutputStream(Files.newOutputStream(zipPath)))) < Files.createDirectory(foldertozip); Files.createDirectory(foldertozip.resolve("emptydir")); Files.writeString(dirFile1, "Does this Java get you rev'd up or what?"); Files.writeString(dirFile2, "Java Java Java . Buz Buz Buz!"); Files.walk(foldertozip).forEach(path -> < try < var reliativePath = inputDataDir.relativize(path); var file = path.toFile(); if (file.isDirectory()) < var files = file.listFiles(); if (files == null || files.length == 0) < zos.putNextEntry(new ZipEntry( reliativePath.toString() + File.separator)); zos.closeEntry(); >> else < zos.putNextEntry(new ZipEntry(reliativePath.toString())); zos.write(Files.readAllBytes(path)); zos.closeEntry(); >> catch(IOException e) < e.printStackTrace(); >>); > catch(IOException e) < e.printStackTrace(); >>
Заключение
В этой статье я обсудил и продемонстрировал современный подход к работе с zip-архивами на Java с использованием чистой Java и без сторонних библиотек. Вы также можете заметить, что я использую еще несколько современных функций языка Java, таких как парадигмы функционального программирования и var для предполагаемых переменных, поэтому при выполнении этих примеров убедитесь, что вы используете как минимум Java 10.
Как всегда, спасибо за чтение и не стесняйтесь комментировать или критиковать ниже.
Licensed under CC BY-NC-SA 4.0
Class ZipFile
Unless otherwise noted, passing a null argument to a constructor or method in this class will cause a NullPointerException to be thrown.
Field Summary
Constructor Summary
Method Summary
Methods declared in class java.lang.Object
Field Details
OPEN_READ
OPEN_DELETE
Mode flag to open a zip file and mark it for deletion. The file will be deleted some time between the moment that it is opened and the moment that it is closed, but its contents will remain accessible via the ZipFile object until either the close method is invoked or the virtual machine exits.
LOCSIG
EXTSIG
CENSIG
ENDSIG
LOCHDR
EXTHDR
CENHDR
ENDHDR
LOCVER
LOCFLG
LOCHOW
LOCTIM
LOCCRC
LOCSIZ
LOCLEN
LOCNAM
LOCEXT
EXTCRC
EXTSIZ
EXTLEN
CENVEM
CENVER
CENFLG
CENHOW
CENTIM
CENCRC
CENSIZ
CENLEN
CENNAM
CENEXT
CENCOM
CENDSK
CENATT
CENATX
CENOFF
ENDSUB
ENDTOT
ENDSIZ
ENDOFF
ENDCOM
Constructor Details
ZipFile
Opens a zip file for reading. First, if there is a security manager, its checkRead method is called with the name argument as its argument to ensure the read is allowed. The UTF-8 charset is used to decode the entry names and comments.
ZipFile
Opens a new ZipFile to read from the specified File object in the specified mode. The mode argument must be either OPEN_READ or OPEN_READ | OPEN_DELETE . First, if there is a security manager, its checkRead method is called with the name argument as its argument to ensure the read is allowed. The UTF-8 charset is used to decode the entry names and comments
ZipFile
Opens a ZIP file for reading given the specified File object. The UTF-8 charset is used to decode the entry names and comments.
ZipFile
Opens a new ZipFile to read from the specified File object in the specified mode. The mode argument must be either OPEN_READ or OPEN_READ | OPEN_DELETE . First, if there is a security manager, its checkRead method is called with the name argument as its argument to ensure the read is allowed.
ZipFile
Opens a zip file for reading. First, if there is a security manager, its checkRead method is called with the name argument as its argument to ensure the read is allowed.
ZipFile
Method Details
getComment
getEntry
getInputStream
Returns an input stream for reading the contents of the specified zip file entry. Closing this ZIP file will, in turn, close all input streams that have been returned by invocations of this method.
getName
entries
stream
Returns an ordered Stream over the ZIP file entries. Entries appear in the Stream in the order they appear in the central directory of the ZIP file.
size
close
Closes the ZIP file. Closing this ZIP file will close all of the input streams previously returned by invocations of the getInputStream method.
Report a bug or suggest an enhancement
For further API reference and developer documentation see the Java SE Documentation, which contains more detailed, developer-targeted descriptions with conceptual overviews, definitions of terms, workarounds, and working code examples. Other versions.
Java is a trademark or registered trademark of Oracle and/or its affiliates in the US and other countries.
Copyright © 1993, 2023, Oracle and/or its affiliates, 500 Oracle Parkway, Redwood Shores, CA 94065 USA.
All rights reserved. Use is subject to license terms and the documentation redistribution policy.