1

Here is the backend code for the download endpoint:

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ZipOutputStream zipOut = new ZipOutputStream(byteArrayOutputStream);
for (Long id : ids) {
    // Get the "generated" file using the id    
    zipOut.putNextEntry(new ZipEntry(generated.getName() + ".doc"));
    InputStream inputStream = new ByteArrayInputStream(generated.getFile().getBytes(1, (int)generated.getFile().length()));
    IOUtils.copy(inputStream, zipOut);
    zipOut.closeEntry();
}
zipOut.close();

response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=File.zip");

byte[] zipBytes = byteArrayOutputStream.toByteArray();
OutputStream outputStream = response.getOutputStream();
outputStream.write(zipBytes);
outputStream.close();
response.flushBuffer();

And for the frontend, I am using axios and file-saver

import { saveAs } from "file-saver";

request.then((response: any) => {
  const blob = new Blob([response.data], { type: "application/zip" });
  saveAs(blob, "Report.zip");
});

I can download the zip file, but when I tried to open, I got the follwing error:

"An attempt was made to move the file pointer before the beginning of the file"

NOTE: There is no error on the backend. The zip file is downloaded successfully. But upon opening the zip file, the error pops up.

iPhoneJavaDev
  • 821
  • 5
  • 33
  • 78
  • 1
    Don't close the outputstream from the response, that is the responsibility of the servlet container. Also why not directly write to the outputstream instead of first to a `ByteArrayOutputStream`? That would save you memory and increase performance. Finally what does `getFile()` return? As `getBytes` takes an index, it generally should start at 0 not 1. – M. Deinum Sep 22 '21 at 05:18
  • your solution doesn't work. getFile() returns a blob, setting it to 1 will result to exception. i already tested this by saving to local and the zip file is generated and i can open it.. but when i send it over to the browser, though i can see the content of the zip file bytes in the network preview, opening the downloaded zip file shows this error. – iPhoneJavaDev Sep 22 '21 at 09:00
  • Which is why I asked what `getFile` returns. You also failed to mentioned that saving locally to a file does work. However as I stated you shouldn't close the outputstream as that risks closing it to early before everything has been flushed/send. So don't close and I would strongly suggest to remove the intermediate `ByteArrayOutputStream` for memory and performance reasons. Finally if it is a `Blob` why not use `getBinaryStream` to get the content instead of a `byte[]` should save some memory as well? – M. Deinum Sep 22 '21 at 09:11
  • i already did what you said and it doesn't work. – iPhoneJavaDev Sep 22 '21 at 10:12
  • Have you tried with a different zip file ? – moi Sep 25 '21 at 16:59

1 Answers1

1

Please, try to rewrite it like that:

response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=File.zip");

ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream());
for (Long id : ids) {
    // Get the "generated" file using the id    
    zipOut.putNextEntry(new ZipEntry(generated.getName() + ".doc"));
    InputStream inputStream = new ByteArrayInputStream(generated.getFile().getBytes(1, (int)generated.getFile().length()));
    IOUtils.copy(inputStream, zipOut);
    zipOut.closeEntry();
}
zipOut.close();
response.flushBuffer(); 
Denis Rodin
  • 319
  • 1
  • 7