The project was started and coded by Rein Raudjärv when he needed to process a large set of large ZIP archives for LiveRebel internals. Soon after we started using the utility in other projects because of the ease of use and it just worked.
The project is built using java.util.zip.* packages for stream based access. Most convenience methods for filesystem usage is also supported.
The project artifacts are available in Maven Central Repository. To include it in your maven project then you have to specify the dependency.
...
<dependency>
<groupId>org.zeroturnaround</groupId>
<artifactId>zt-zip</artifactId>
<version>1.17</version>
<type>jar</type>
</dependency>
...
Notice that 1.8 is the last Java 1.4 compatible release. Since then Java 1.5 is required.
If you are using with ProGuard, please add the following configuration
-dontwarn org.slf4j.**
We had the following functional requirements:
and these non-functional requirements:
The examples don't include all the possible ways how to use the library but will give an overview. When you see a method that is useful but doesn't necessarily solve your use case then just head over to ZipUtil.class file and see the sibling methods that are named the same but arguments might be different.
boolean exists = ZipUtil.containsEntry(new File("/tmp/demo.zip"), "foo.txt");
byte[] bytes = ZipUtil.unpackEntry(new File("/tmp/demo.zip"), "foo.txt");
byte[] bytes = ZipUtil.unpackEntry(new File("/tmp/demo.zip"), "foo.txt", Charset.forName("IBM437"));
ZipUtil.unpackEntry(new File("/tmp/demo.zip"), "foo.txt", new File("/tmp/bar.txt"));
ZipUtil.unpack(new File("/tmp/demo.zip"), new File("/tmp/demo"));
ZipUtil.explode(new File("/tmp/demo.zip"));
ZipUtil.unpack(new File("/tmp/demo.zip"), new File("/tmp/demo"), new NameMapper() {
public String map(String name) {
return name.startsWith("doc/") ? name : null;
}
});
final String prefix = "doc/";
ZipUtil.unpack(new File("/tmp/demo.zip"), new File("/tmp/demo"), new NameMapper() {
public String map(String name) {
return name.startsWith(prefix) ? name.substring(prefix.length()) : name;
}
});
ZipUtil.unpack(new File("/tmp/demo.zip"), new File("/tmp/demo"), new NameMapper() {
public String map(String name) {
if (name.contains("/doc")) {
return name;
}
else {
// returning null from the map method will disregard the entry
return null;
}
}
});
ZipUtil.iterate(new File("/tmp/demo.zip"), new ZipInfoCallback() {
public void process(ZipEntry zipEntry) throws IOException {
if (zipEntry.getName().endsWith(".class"))
System.out.println("Found " + zipEntry.getName());
}
});
ZipUtil.iterate(new File("/tmp/demo.zip"), new ZipEntryCallback() {
public void process(InputStream in, ZipEntry zipEntry) throws IOException {
if (zipEntry.getName().endsWith(".txt")) {
System.out.println("Found " + zipEntry.getName());
IOUtils.copy(in, System.out);
}
}
});
ZipUtil.pack(new File("/tmp/demo"), new File("/tmp/demo.zip"));
ZipUtil.unexplode(new File("/tmp/demo.zip"));
ZipUtil.pack(new File("/tmp/demo"), new File("/tmp/demo.zip"), new NameMapper() {
public String map(String name) {
return "foo/" + name;
}
});
ZipUtil.packEntry(new File("/tmp/demo.txt"), new File("/tmp/demo.zip"));
ZipUtil.addEntry(new File("/tmp/demo.zip"), "doc/readme.txt", new File("f/tmp/oo.txt"), new File("/tmp/new.zip"));
ZipUtil.addEntry(new File("/tmp/demo.zip"), "doc/readme.txt", "bar".getBytes(), new File("/tmp/new.zip"));
ZipEntrySource[] entries = new ZipEntrySource[] {
new FileSource("doc/readme.txt", new File("foo.txt")),
new ByteSource("sample.txt", "bar".getBytes())
};
ZipUtil.addEntries(new File("/tmp/demo.zip"), entries, new File("/tmp/new.zip"));
ZipEntrySource[] entries = new ZipEntrySource[] {
new FileSource("doc/readme.txt", new File("foo.txt")),
new ByteSource("sample.txt", "bar".getBytes())
};
OutputStream out = null;
try {
out = new BufferedOutputStream(new FileOutputStream(new File("/tmp/new.zip")));
ZipUtil.addEntries(new File("/tmp/demo.zip"), entries, out);
}
finally {
IOUtils.closeQuietly(out);
}
boolean replaced = ZipUtil.replaceEntry(new File("/tmp/demo.zip"), "doc/readme.txt", new File("/tmp/foo.txt"), new File("/tmp/new.zip"));
boolean replaced = ZipUtil.replaceEntry(new File("/tmp/demo.zip"), "doc/readme.txt", "bar".getBytes(), new File("/tmp/new.zip"));
ZipEntrySource[] entries = new ZipEntrySource[] {
new FileSource("doc/readme.txt", new File("foo.txt")),
new ByteSource("sample.txt", "bar".getBytes())
};
boolean replaced = ZipUtil.replaceEntries(new File("/tmp/demo.zip"), entries, new File("/tmp/new.zip"));
ZipEntrySource[] addedEntries = new ZipEntrySource[] {
new FileSource("/path/in/zip/File1.txt", new File("/tmp/file1.txt")),
new FileSource("/path/in/zip/File2.txt", new File("/tmp/file2.txt")),
new FileSource("/path/in/zip/File3.txt", new File("/tmp/file2.txt")),
};
ZipUtil.addOrReplaceEntries(new File("/tmp/demo.zip"), addedEntries);
boolean transformed = ZipUtil.transformEntry(new File("/tmp/demo"), "sample.txt", new StringZipEntryTransformer() {
protected String transform(ZipEntry zipEntry, String input) throws IOException {
return input.toUpperCase();
}
}, new File("/tmp/demo.zip"));
boolean equals = ZipUtil.archiveEquals(new File("/tmp/demo1.zip"), new File("/tmp/demo2.zip"));
boolean equals = ZipUtil.entryEquals(new File("/tmp/demo1.zip"), new File("/tmp/demo2.zip"), "foo.txt");
boolean equals = ZipUtil.entryEquals(new File("/tmp/demo1.zip"), new File("/tmp/demo2.zip"), "foo1.txt", "foo2.txt");
There have been multiple requests for a progress bar. See ZT Zip Progress Bar for a sample implementation.
The library is using the slf4j-api logging framework. All the log statements are either DEBUG or TRACE level. Depending on the logging framework you are using a simple -Dorg.slf4j.simpleLogger.defaultLogLevel=debug
or System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "debug");
will do the trick of showing log statements from the zt-zip library. You can further fine tune the levels and inclusion of log messages per package with your logging framework.