How can I append files to an existing zip file? I already have the code that can create a zip file and it works great except for one big problem. The way it works now, the user takes a bunch of pictures, and at the end, all the pictures get added to a zip file, which can take quite a while if you take enough pictures. :-( So I'm thinking, I have a very good and efficient solution. As the pictures are taken, I will simply add the each new picture to the zip file right after it's taken. Then when they're done taking pictures, finish up the zip file so it's usable and export it. :-)
The problem is, I can not get it to add files to an existing zip file. :-( Here's what I have so far. Also, please keep in mind, this is just a proof of concept, I do understand that re-initializing everything for every iteration of the for loop is very dumb. Each iteration of the loop is supposed to represent another file being added which will most likely be a long time later, maybe even an hour later, which is why I have everything resetting each iteration, because the app will be shut down between adding files. If I can get this working, then I will actually ditch the for loop and put this code into a function that gets called every time a picture gets taken. :-)
try {
for(int i=0; i < _files.size(); i++) {
//beginning of initial setup stuff
BufferedInputStream origin = null;
FileOutputStream dest = new FileOutputStream(_zipFile,false);
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest));
byte data[] = new byte[BUFFER];
out.setLevel(0); //I added this because it makes it not compress the data
//at all and I hoped that it would allow the zip to be appended to
//end of initial setup stuff
//beginning of old for loop
Log.v("Compress", "Adding: " + _files[i]);
FileInputStream fi = new FileInputStream(_files[i]);
origin = new BufferedInputStream(fi, BUFFER);
ZipEntry entry = new ZipEntry(_files[i].substring(_files[i].lastIndexOf("/") + 1));
out.putNextEntry(entry);
int count;
while ((count = origin.read(data, 0, BUFFER)) != -1) {
out.write(data, 0, count);
}
origin.close();
//end of for old loop
//beginning of finishing stuff
out.close();
//end of finishing stuff
}
} catch(Exception e) {
Log.e("ZipCreation", "Error writing zip", e);
e.printStackTrace();
}
Also, I have experimented around with
FileOutputStream dest = new FileOutputStream(_zipFile,true);
If you notice, I set append to true, which will actually append the data to an existing file. And what's interesting is, it actually does append the data to the original file, however, after the file gets extracted on my computer, the last file written is all that gets extracted, which is bad. :-( So is there some way to start writing a zip file, and then later, add on to it, and finish up the zip file? I've even thought about possibly taking ZipOutputStream and modifying it to fit this model that I need. It should logically be possible somehow? :-)
Thanks in advance for the help! :-D
-Jared
Ok, thanks for all your suggestions, but I was able to get it working like I wanted.... it CAN be done, you CAN add files after closing the file, as long as you save your place!!! :-D
Here's how I was able to get it going working:
Also, keep in mind, this is not the only code I had to do. I also had to make my own copy of ZipOutputStream so that I could expose the following functions that I created within my ZipOutputStreamNew class....
as well as
For the most part, all this does, is it starts writing like normal, then, instead of closing like normal, it backs up those two variables, and then for the next iteration, it restores just those variables.
Let me know if you have any questions about all this, but I knew it would work, all it has to do is save where it was. :-D
Thanks again for all the help everybody! :-)
At Raj's request, here is the source code for ZipOutputStreamNew:
I believe it can't be done right now with the current API.
You can append data to any file, but that does not mean that you will end up with the right file format. A
.zip
file is not like a.tar
file, and the compression requires imposes restrictions to the handling of the files (file positions, EOF, etc.). If you consider the structure of the file format (taken from wikipedia here) you will understand why just appending does not work.There is a library called TrueZip that could work, although I do not know if it supports android. Take a look at this answer in another similar question: Appending files to a zip file with Java .
Also, as a workaround, you could create individual
.zip
files and append them as a tarball (file format here). Compression might be slighty worst, but it would be much better in terms of time efficiency.Update based on the comments (and possible solution)
You could separate the addition to each
ZipEntry
and leave theZipOutputStream
object open as long as you are still taking pictures. I can see risks with that approach, though, as any problem with the app while still taking pictures (a force close, run out of battery, etc) may render the whole file unusable. You will need to make sure to use the right try/catch/finally blocks to close the file and callcloseZip()
upon events such asonClose()
andonDestroy()
, but the idea would be the following: