Issue
I've setup a method that feeds in multiple data files from our S3 bucket in an attempt to zip them together and then pass them to the user querying via the browser. However, I can't open the file that gets sent back.
I've tested with a FileOutputStream and the zip files stores in a proper format there, so it looks like the process of pulling, zipping and writing are working.
My assumption that there's an issue passing it back via the ServletOutputStream, which is pulled using the getResponse().getOutputStream()
that you see below. I then call the write method on it, and this process seems to work fine for single files in byte[] format in other parts of the program, just not here.
Another piece to the puzzle, the file in zip format that I output and that worked via FileOutputStream was the same size as the file delivered via the browser and ServletOutputStream, so I think the data is getting over. Instead though I just get an (Error 79 - Inappropriate file type or format.)
Open to any suggestions or help!!
File file;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(byteArrayOutputStream);
for (String fileName : fileList) {
key = fileName.replaceAll("=", "%3D");
file = s3Client.get(bucket, key, Paths.get("/tmp/" + fileName));
FileInputStream fis = new FileInputStream(file);
ZipEntry zipEntry = new ZipEntry(fileName);
zos.putNextEntry(zipEntry);
//Buffer used to read input stream
byte[] buffer = new byte[4096];
int length;
while ((length = fis.read(buffer)) != -1) {
//Read input stream to buffer and write this to zip output stream
zos.write(buffer, 0, length);
}
zos.closeEntry();
fis.close();
}
zos.flush();
getResponse().setContentType("application/zip");
getResponse().setContentLength(byteArrayOutputStream.size());
getResponse().setHeader("Content-Disposition", "attachment; filename=\"" + "test" + "." + "zip" + "\"");
getResponse().setHeader("Connection", "keep-alive");
getResponse().setHeader("Cache-Control", "private");
getResponse().setHeader("Pragma", "private");
getResponse().setDateHeader("Expires", System.currentTimeMillis() + 300000);
getResponse().getOutputStream().write(byteArrayOutputStream.toByteArray());
getResponse().getOutputStream().flush();
zos.close();
byteArrayOutputStream.close();
Solution
You haven't closed the ZipOutputStream
correctly - the call to zos.close();
must occur before writing the bytes, not afterwards.
You can get much neater handling of the output if using try with resources block and Files.copy
:
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try(ZipOutputStream zos = new ZipOutputStream(byteArrayOutputStream)) {
for (String fileName : fileList) {
key = fileName.replaceAll("=", "%3D");
Path file = s3Client.get(bucket, key, Paths.get("/tmp/" + fileName)).toPath();
ZipEntry zipEntry = new ZipEntry(fileName);
zos.putNextEntry(zipEntry);
Files.copy(file, zos);
}
};
getResponse().setContentType("application/zip");
getResponse().setContentLength(byteArrayOutputStream.size());
getResponse().setHeader("Content-Disposition", "attachment; filename=\"" + "test" + "." + "zip" + "\"");
getResponse().setHeader("Connection", "keep-alive");
getResponse().setHeader("Cache-Control", "private");
getResponse().setHeader("Pragma", "private");
getResponse().setDateHeader("Expires", System.currentTimeMillis() + 300000);
getResponse().getOutputStream().write(byteArrayOutputStream.toByteArray());
getResponse().getOutputStream().flush();
Answered By - DuncG
Answer Checked By - David Marino (JavaFixing Volunteer)