Reputation: 145
I have this Java code that creates and saves a zip file with a text file inside it:
public static void main(String[] args) {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos)) {
String s = "Hello, world!";
ZipEntry entry = new ZipEntry("text_file.txt");
zos.putNextEntry(entry);
zos.write(s.getBytes());
zos.closeEntry();
try (OutputStream os = new FileOutputStream("zip_file.zip")) {
baos.writeTo(os);
System.out.println("ZIP file created successfully");
}
} catch (IOException e) {
System.out.println("Error: " + e);
}
}
The problem with this code is that it creates a zip file that is corrupted, so I cannot extract or even open the content within it.
Eventually I found out that if I manually close the ZipOutputStream
by putting zos.close()
after zos.closeEntry()
the zip file is created successfully without corruption. Honestly this does not make any sense to me since I have declared the ZipOutputStream
inside a try-with-resource statement, so I would have expected it to close automatically.
So it seems that the try-with-resource statement does not actually close the stream. Am I doing something wrong?
Any help would be appreciated.
OS: Windows 10
Note: I used ByteArrayOutputStream
because in the real scenario I have to create the zip file in memory, since I don't have a folder on a disk to rely on.
Upvotes: 2
Views: 2504
Reputation: 29
To keep everything in same Try-catch, another approach is to finish & flush the ZipOutputStream before using the content of ByteArrayOutputStream inside it (which can be incomplete, this is why it may generate corrupted zip), for example :
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos)) {
//codes insert into zip
zos.finish(); //finish writing
zos.flush(); //flush any buffer inside
//use baos
} catch (IOException e) {
System.out.println("Error: " + e);
}
Upvotes: 0
Reputation: 145
It turned out that I was misplacing the ByteArrayOutputStream
object: I should have not closed it by placing it inside the try-with-resource statement because, as explained here, ByteArrayOutputStream
is purely memory based so the allocated memory will be released automatically by the garbage collector.
The following code produces the desired result:
public static void main(String[] args) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
String s = "Hello, world!";
ZipEntry entry = new ZipEntry("text_file.txt");
zos.putNextEntry(entry);
zos.write(s.getBytes());
zos.closeEntry();
} catch (IOException e) {
System.out.println("Error: " + e);
}
try (OutputStream os = new FileOutputStream("zip_file.zip")) {
baos.writeTo(os);
System.out.println("ZIP file created successfully");
} catch (IOException e) {
System.out.println("Error: " + e);
}
}
Upvotes: 0
Reputation: 269697
The try-with-resources
does close the ZipOutputStream
. It's just that it closes the zip stream after you copy its content to the FileOutputStream
. How do you expect work that happens after the file has been closed to affect the content of the file?
I recommend replacing the ByteArrayOutputStream
with the FileOutputStream
. What need do you have to buffer?
try (OutputStream os = new FileOutputStream("zip_file.zip");
ZipOutputStream zos = new ZipOutputStream(os)) {
String s = "Hello, world!";
ZipEntry entry = new ZipEntry("text_file.txt");
zos.putNextEntry(entry);
zos.write(s.getBytes());
zos.closeEntry();
}
System.out.println("ZIP file created successfully");
Upvotes: 2