Reputation: 1411
I have a zip file file.zip
that is compressed. Is there a way to change the compression level of the file to store (no compression).
I have written and tried the following code and it works, but I will be running this in an environment where memory and storage will be a limitation and there might not be enough space. I am using the zip4j library.
This code extracts the input zip to a folder, then rezips it with store compression level. The problem with this is that at one point in execution, there are 3 copies of the zip on storage, which is a problem because space is a limitation.
try {
String zip = "input.zip";
final ZipFile zipFile = new ZipFile(zip);
zipFile.extractAll("dir");
File file = new File("dir");
ZipParameters params = new ZipParameters();
params.setCompressionMethod(Zip4jConstants.COMP_STORE);
params.setIncludeRootFolder(false);
ZipFile output = new ZipFile(new File("out.zip"));
output.addFolder(file, params);
file.delete();
return "Done";
} catch (Exception e) {
e.printStackTrace();
return "Error";
}
So any suggestions on another way to approach this problem? Or maybe some speed or memory optimizations to my current code?
Upvotes: 3
Views: 1507
Reputation: 1411
I finally got it after a few hours by playing around with input streams.
try {
final ZipFile zipFile = new ZipFile("input.zip");
File output = new File("out.zip");
byte[] read = new byte[1024];
ZipInputStream zis = new ZipInputStream(new FileInputStream(zip));
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(output));
ZipEntry ze;
zos.setLevel(ZipOutputStream.STORED);
zos.setMethod(ZipOutputStream.STORED);
while((ze = zis.getNextEntry()) != null) {
int l;
zos.putNextEntry(ze);
System.out.println("WRITING: " + ze.getName());
while((l = zis.read(read)) > 0) {
zos.write(read, 0, l);
}
zos.closeEntry();
}
zis.close();
zos.close();
return "Done";
} catch (Exception e) {
e.printStackTrace();
return "Error";
}
Thanks so much for your answer Evgeniy Dorofeev, I literally just got my answer when I read yours! However, I prefer my method as it only takes up a maximum of 1 MB in memory (Am I right?). Also, I tried executing your code and only the first file in the input zip was transferred.
Upvotes: 0
Reputation: 136012
As an alternative we can read files from zip one by one in memory or into temp file, like here
ZipInputStream is = ...
ZipOutputStream os = ...
os.setMethod(ZipOutputStream.STORED);
int bSize = ... calculate max available size
byte[] buf = new byte[bSize];
for (ZipEntry e; (e = is.getNextEntry()) != null;) {
ZipEntry e2 = new ZipEntry(e.getName());
e2.setMethod(ZipEntry.STORED);
int n = is.read(buf);
if (is.read() == -1) {
// in memory
e2.setSize(n);
e2.setCompressedSize(n);
CRC32 crc = new CRC32();
crc.update(buf, 0, n);
e2.setCrc(crc.getValue());
os.putNextEntry(e2);
os.write(buf, 0, n);
is.closeEntry();
os.closeEntry();
} else {
// use tmp file
}
}
reading in memory is supposed to be faster
Upvotes: 1