How to Read Files from a Zip File in Java
Reading a zip file means looking at the entries inside an archive and, if needed, reading or extracting their contents. Java offers two classes in java.util.zip. ZipFile opens a zip file on disk and lets you list and read entries in any order. ZipInputStream reads a zip as a stream, one entry after another, which also works for zips arriving over the network. In this lesson, you will learn both, print every file in an archive, and extract files safely.
Classes and Methods
| Class / method | Description |
|---|---|
new ZipFile(file) | It is used to open a zip file for random access to its entries. |
zipFile.stream() / entries() | It returns all entries. |
zipFile.getInputStream(entry) | It reads one entry's contents. |
new ZipInputStream(in) | It reads a zip sequentially from any stream. |
zin.getNextEntry() | It moves to the next entry, or returns null at the end. |
entry.getName(), getSize(), isDirectory() | It describes an entry. |
Example: Listing and Printing Entries with ZipFile
Let's see an example that creates a small zip and prints every file in it.
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.TreeMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
public class ReadZip {
public static void main(String[] args) throws IOException {
Map<String, String> files = new TreeMap<>(Map.of(
"class/navika.txt", "Marks: 91",
"class/advitha.txt", "Marks: 85"));
try (OutputStream f = Files.newOutputStream(Path.of("class.zip"));
ZipOutputStream out = new ZipOutputStream(f)) {
for (var e : files.entrySet()) {
out.putNextEntry(new ZipEntry(e.getKey()));
out.write(e.getValue().getBytes(StandardCharsets.UTF_8));
out.closeEntry();
}
}
try (ZipFile zip = new ZipFile("class.zip")) {
System.out.println(zip.size() + " entries");
for (ZipEntry entry : zip.stream().toList()) {
try (InputStream in = zip.getInputStream(entry)) {
String text = new String(in.readAllBytes(),
StandardCharsets.UTF_8);
System.out.println(entry.getName() + " (" + entry.getSize()
+ " bytes): " + text);
}
}
}
}
}2 entries
class/advitha.txt (9 bytes): Marks: 85
class/navika.txt (9 bytes): Marks: 91Explanation: The first part builds a zip with two entries. ZipFile then opens it, stream() lists the entries, and getInputStream(entry) reads each one. getSize() gives the uncompressed size.
Example: Extracting Safely with ZipInputStream
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public class Extract {
public static void main(String[] args) throws IOException {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try (ZipOutputStream out = new ZipOutputStream(bytes)) {
String[] names = {"notes/srihitha.txt", "../evil.txt"};
for (String name : names) {
out.putNextEntry(new ZipEntry(name));
out.write("hello".getBytes());
out.closeEntry();
}
}
Path target = Files.createDirectories(Path.of("unzipped"))
.toAbsolutePath().normalize();
try (ZipInputStream in = new ZipInputStream(
new ByteArrayInputStream(bytes.toByteArray()))) {
ZipEntry entry;
while ((entry = in.getNextEntry()) != null) {
Path dest = target.resolve(entry.getName()).normalize();
if (!dest.startsWith(target)) {
System.out.println("Blocked: " + entry.getName());
continue;
}
Files.createDirectories(dest.getParent());
Files.copy(in, dest);
System.out.println("Extracted: " + target.relativize(dest));
}
}
}
}Extracted: notes/srihitha.txt
Blocked: ../evil.txtExplanation: getNextEntry moves through the archive one entry at a time, and Files.copy(in, dest) copies the current entry's bytes. Before writing, each destination is normalized and checked to be inside the target folder. The entry named ../evil.txt would escape the folder, so it is blocked. This attack is called zip slip.
Common Mistakes
Extracting entry names without checking them. A crafted name can overwrite files outside the target.
Using ZipFile for a zip that is still downloading. Use ZipInputStream for streams.
Trusting getSize(). It can be -1 when unknown; read until the end of the entry instead.
Practice
- Easy: List the names and sizes of all entries in a zip file you create.
- Harder: Write
unzip(Path zip, Path target)that extracts every entry safely, creating folders as needed and skipping unsafe names.
Key Takeaways
Was this tutorial helpful?