Today you will learn how you can use Java to Zip a file with an example.
Although it is a very basic and beginner friendly tutorial. You can refresh your knowledge on zipping files with Java, and it will work for you.
Without any further ado let us begin with the process. Here to zip the file we are not using any additional libraries.
Every class used here is from the packages java.io.* and java.util.*.
Now let us first break down the portion of the ZipHelper.java
file method by method.
Quick Navigation
Creating Zip Helper Java Class
We will be using a class named ZipHelper
to perform our operations. So, let us first create that class and it’s necessary constructor.
public class ZipHelper {
private final File source;
private final ZipOutputStream zipOutputStream;
private final Stack<File> stackOfFilesToBeZipped;
public ZipHelper(File source, File destination) throws FileNotFoundException {
// the source file and the destination file
// can be a single file or a directory
this.source = source;
final FileOutputStream fileOutputStream = new FileOutputStream(destination);
zipOutputStream = new ZipOutputStream(fileOutputStream);
// the level of compression can be either of 2; ZipEntry.STORED or ZipEntry.DEFLATED
zipOutputStream.setLevel(ZipEntry.STORED);
// optional if you want to add comment to the zip file
// zipOutputStream.setComment("don't forget to bookmark http://nepdev.xyz");
stackOfFilesToBeZipped = new Stack<>();
// count total files to be zipped
recursivelyAddFilesToStack(source);
System.out.println("there are " + stackOfFilesToBeZipped.size() + " files to be zipped.");
}
}
Code language: Java (java)
The code above is pretty clear we create a ZipOutputStream
and stack of files with Stack<File>
.
The method recursivelyAddFilesToStack()
is does not exist yet. This will be covered in the section below this. Let us move onto that then.
Recursively Find Files in Directory
First let us look at recursively listing out the contents of a directory.
public class ZipHelper {
private final Stack<File> stackOfFilesToBeZipped;
private void recursivelyAddFilesToStack(File file) {
if (file.isFile()) {
stackOfFilesToBeZipped.add(file);
return;
}
File[] files = file.listFiles();
if (files == null) {
// directory is empty
return;
}
for (File item : files) {
recursivelyAddFilesToStack(item);
}
}
}
Code language: Java (java)
In the code above we are recursively scanning files in the child directories. This can be done with file walker in Java 8+
but I’m keeping it simple.
But here’s what we did in the code above:
- First we checked if the passed file instance is a file or a directory. If it is we add to our stack and finish our execution.
- Next, we list the files in current directory. And check if resulting array is null, if the resulting array is null then it means the directory is empty.
- Then, we pass the children to the same method recursively from inside a loop.
The code above is invoked from the constructor of the ZipHelper
class.
Zip File in Java
Now after we have enumerated the contents of java recursively. Let us look at how we can add file to a zip in Java.
This process isn’t really involved but you have to be careful about somethings. Take notes of these things:
- The files you add in the zip should have a relative path from the root and not the absolute path
- You have to create an entry and close it after each write
What are we going to do to complete our example ? Glad you had that same question in mind. Let me lay out a pseudo(ish) code structure.
- Loop through and pass each files in the stack from section above to
zipFile()
- Create a zip entry with a relative path name ( see note above )
- Open a file input stream for the file to be added using absolute path ( see note above )
- Get the bytes from
FileInputStream
and write toZipOutputStream
- Close the entry and the
FileInputStream
That is all that we are going to be doing. Now let us see the code for the algorithm above.
public class ZipHelper {
public static final int BUFFER_SIZE = 1024 * 8;
public static final int EOF = -1;
public static final int OFFSET_START = 0;
public static final int SUBSTRING_OFFSET = 1;
public static final String EMPTY = "";
private final File source;
private final ZipOutputStream zipOutputStream;
private final Stack<File> stackOfFilesToBeZipped;
/**
* Start the zip operation.
*
* @throws IOException
*/
public void zip() throws IOException {
while (true) {
// looks like we have completed our zipping task
if (stackOfFilesToBeZipped.empty()) {
zipOutputStream.close();
break;
}
// pop file from satck and add to zip
zipFile(stackOfFilesToBeZipped.pop());
}
}
/**
* Zip a single file appropriately into the destination zip file.
*
* @param file the file that should be zipped.
* @throws IOException
*/
private void zipFile(File file) throws IOException {
String relativePath = file.getAbsolutePath().replace(source.getAbsolutePath(), EMPTY);
if (relativePath.isEmpty()) {
// relativePath will be empty for a single file
// so to fix that we must add only that file's filename
relativePath = source.getName();
} else {
// we do not want the forward slash /
// so for all other path we have to trim out the first character i.e. /
relativePath = relativePath.substring(SUBSTRING_OFFSET);
}
ZipEntry zipEntry = new ZipEntry(relativePath);
zipOutputStream.putNextEntry(zipEntry);
// write the data to output file
final FileInputStream fileInputStream = new FileInputStream(file);
final byte[] buffer = new byte[BUFFER_SIZE];
int readBytes;
while (true) {
readBytes = fileInputStream.read(buffer);
if (readBytes == EOF) break;
zipOutputStream.write(buffer, OFFSET_START, readBytes);
}
fileInputStream.close();
zipOutputStream.closeEntry();
}
}
Code language: Java (java)
In the code above we will expose zip()
method and not the zipFile()
. zipFile()
will be used internally.
The code above is pretty self explanatory. But if you are new to file handling or programming in general then you might find it a bit complicated.
Everything has been outlined above except for ZipEntry
. What is it ?
Since a zip file is essentially just a container. ZipEntry
is a class defines the actual bounds of the file that we put in. In other words ZipEntry
will define where each file is.
Stitching the Pieces
The code above is provided for explanation. You can find the source code here in this gist.
And for the usage example. You must be familiar with multi threading. You might ask: Why ?
It is simply because the zip operation might take some time. And if you perform the operation on MainThread
. There will be issues. I primarily write codes for Android platform so this is for Android developers.
Let us use handler thread for this task, learn more if you want but here is a simple example for the use of the class.
public void addToZip() {
HandlerThread handlerThread = new HandlerThread("CompressionThread");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
handler.post(new Runnable() {
@Override
public void run() {
try {
// change this to your own path
File destinationZipFile = new File("/storage/emulated/0/", "my_zip_file.zip");
ZipHelper zm = new ZipHelper(new File("/storage/emulated/0/folder_to_be_zipped"), destinationZipFile);
zm.zip();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
Code language: Java (java)
The code above is simply a method demonstrating the use of ZipHelper
.
You can use the above method and add it to your Android Activity
class or some other portion where you want to perform the zip operation.
That is it for this tutorial demonstrating Java zip example.
Recommended
Radio Button in Android: Learn Basics and Customization
Java List Data Structure: Learn Real Use Case Of List
Android Activity Lifecycle: It’s Not That Hard