All about java zip

Working with Zip Files in Java

In this article I cover the basics of creating, interacting with, inspecting, and extracting zip archive files using Java (OpenJDK 11 to be specific). The code sample used in this article is in the form of a Gradle project and hosted in this GitHub repo for you to run and experiment with. Please exercise caution when changing code that deletes files.

As mentioned already, the code examples here are written in using Java 11 and utilizes the var keyword which was introduced in Java 10 and functional programming paradigms in Java 8, so a minimum version of Java 10 is required to run them as is.

Contents

Key Java Classes for Working with Zip Archives

I feel it’s a good idea to start things off by identifying some of the prominent classes that are commonly used when dealing with zip archives in Java. These classes live in either the java.util.zip or java.nio.file packages.

  • java.util.zip.ZipFile is used to read in and interact with items ( ZipEntry instances) in a zip archive
  • java.util.zip.ZipEntry is an abstraction representing a item such as a file or directory in a zip archive (ie, ZipFile instance)
  • java.util.zip.ZipOutputStream is an implementation of the abstract OutputStream class and used to write items to a Zip file
  • java.nio.file.Files is very handy utilities class for streaming and copying file data into ZipOutputStream instances or out of ZipFile instances
  • java.nio.file.Path another handy utilities class for effectively working with file paths
Читайте также:  Setting cookies with php

Common File Paths for the Code Examples

For the example code I use two common directories to write and read data to/from which are both relative to the root of the Gradle project. Take a look at the linked Repo in the introduction, or better yet, run the samples. Just keep these two Path variables in mind as they are used often as the starting directory for inputs and outputs.

public class App < static final Path zippedDir = Path.of("ZippedData"); static final Path inputDataDir = Path.of("InputData"); // . other stuff > 

Inspecting the Contents of a Zip Archive

You can instantiate a ZipFile class and pass it the path to an existing zip archive, which essentially opens it like any other file, then inspect the contents by querying the ZipEntry enumeration contained inside it. Note that ZipFile implements the AutoCloseable interface, making it a great candidate for the try-with-resources Java programming construct shown below and throughout the examples here.

static void showZipContents() < try (var zf = new ZipFile("ZipToInspect.zip")) < System.out.println(String.format("Inspecting contents of: %s\n", zf.getName())); Enumeration zipEntries = 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(); >> 

Running the Gradle project using the following:

This yields output for the App.showZipContents method of:

> 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 

Here you can see that this prints out all files and directories in the zip archive, even the files within directories.

Читайте также:  Http online omnicomm ru new design html

Extracting a Zip Archive

Extracting the contents of a zip archive onto disk requires nothing more than replicating the same directory structure as what is inside the ZipFile , which can be determined via ZipEntry.isDirectory and then copying the files represented in the ZipEntry instances onto disk.

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); Enumeration zipEntries = 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(); >> 

Writing Files Directly into a New Zip Archive

Since writing a zip archive is really nothing more than writing a stream of data to some destination (a Zip file in this case) then writing data, like String data, to a zip archive is only different in that you need to match the data being written to ZipEntry instances added to the ZipOutputStream .

Again, ZipOutputStream implements the AutoCloseable interface, so it is best to use with a try-with-resources statement. The only real catch is to remember to close your ZipEntry when you are done with each one to make it clear when it should no longer receive data.

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(); >> 

Zipping an Existing File into a New Zip Archive

If you’ve copied a File in Java before then you are essentially already a PRO at creating a zip archive from an existing file (or directory for that matter). Again, the only real difference is that you need to take a little extra caution to be sure you are matching files up to the appropriate ZipEntry instances.

In this example I create an input file «FileToZip.txt» and write some data to it «Howdy There Java Friends!» and then use the Files.copy(Path, OutputStream) to associate the ZipEntry with the FileToZip.txt file inside the ZippedFile.zip zip archive I’m creating with a ZipOutoutStream instance.

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(); >> 

Zipping a Folder into a New Zip Archive

Zipping a non-empty directory becomes a little more involved, especially if you want to maintain empty directories within the parent directory. To maintain the presence of an empty directory within a zip archive you need to be sure to create an entry that is suffixed with the file system directory separator when creating it’s ZipEntry , and then immediately close it.

Free eBook: Git Essentials

Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!

In this example I create a directory named «foldertozip» containing the structure shown below, then zip it into a zip archive.

tree . . └── foldertozip ├── emptydir ├── file1.txt └── file2.txt 

In the following code notice that I use the Files.walk(Path) method to traverse the directory tree of «foldertozip» and look for empty directories («emptydir» in this example) and if / when found I concatenate the directory separator to the name within the ZipEntry . After this I close it as soon as I add it to the ZipOutputStream instance.

I also use a slightly different approach to injecting the non-directory files into the ZipOutputStream compared to the last example, but I am just using this different approach for the sake of variety in the examples.

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(); >> 

Conclusion

In this article I have discussed and demonstrated a modern approach to working with zip archives in Java using pure Java and no third party libraries. You may also notice I use a few more modern Java language features, such as functional programming paradigms and the var keyword for type inferred variables, so please make sure you are using at least Java 10 when running these examples.

As always, thanks for reading and don’t be shy about commenting or critiquing below.

Источник

All about java zip

Кроме общего функционала для работы с файлами 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».

Источник

Package java.util.zip

Provides classes for reading and writing the standard ZIP and GZIP file formats. Also includes classes for compressing and decompressing data using the DEFLATE compression algorithm, which is used by the ZIP and GZIP file formats. Additionally, there are utility classes for computing the CRC-32, CRC-32C and Adler-32 checksums of arbitrary input streams.

Package Specification

  • Info-ZIP Application Note 970311 — a detailed description of the Info-ZIP format upon which the java.util.zip classes are based.
  • An implementation may optionally support the ZIP64(tm) format extensions defined by thePKWARE ZIP File Format Specification. The ZIP64(tm) format extensions are used to overcome the size limitations of the original ZIP format.
  • APPENDIX D ofPKWARE ZIP File Format Specification — Language Encoding Flag to encode ZIP entry filename and comment fields using UTF-8.
  • ZLIB Compressed Data Format Specification version 3.3(pdf) (RFC 1950)
  • DEFLATE Compressed Data Format Specification version 1.3(pdf) (RFC 1951)
  • GZIP file format specification version 4.3(pdf) (RFC 1952)
  • CRC-32 checksum is described in RFC 1952 (above)
  • CRC-32C checksum is described in Internet Small Computer Systems Interface (iSCSI)(pdf) (RFC 3720)
  • Adler-32 checksum is described in RFC 1950 (above)

Contains the collections framework, some internationalization support classes, a service loader, properties, random number generation, string parsing and scanning classes, base64 encoding and decoding, a bit array, and several miscellaneous utility classes.

Источник

Оцените статью