8

I have a problem with my created zip file. I am using Java 7. I tried to create a zip file out of a byte array, which contains two or more Excel files. The application finishes allways without any exceptions. So, I thought everything is alright. After I tried to open the zip file, there was an error message from Windows 7, that the zip file is maybe corrupted. I couldn't open it and I have no idea why...! I googled for this problem but the code snippets I found, looks exactly the same than in my implementation.

This is my code:

if (repsList.size() > 1)
{
  String today = DateUtilities.convertDateToString(new Date(), "dd_MM_yyyy");
  String prefix = "recs_" + today;
  String suffix = ".zip";
  ByteArrayOutputStream baos = null;
  ZipOutputStream zos = null;
  try
  {
    baos = new ByteArrayOutputStream();
    zos = new ZipOutputStream(baos);

    for (RepBean rep : repsList)
    {
      String filename = rep.getFilename();
      ZipEntry entry = new ZipEntry(filename);
      entry.setSize(rep.getContent().length);
      zos.putNextEntry(entry);
      zos.write(rep.getContent());
      zos.closeEntry();
    }
    // this is the zip file as byte[]
    reportContent = baos.toByteArray();

  }
  catch (UnsupportedEncodingException e)
  {
    ...
  }
  catch (ZipException e) {
    ...
  }
  catch (IOException e)
  {
    ...
  }
  finally
  {
    try
    {
      if (zos != null)
      {
        zos.close();
      }

      if (baos != null)
      {
        baos.close();
      }
    }
    catch (IOException e)
    {
      // Nothing to do ...
      e.printStackTrace();
    }
  }
}
try
{
  response.setContentLength(reportContent.length);
  response.getOutputStream().write(reportContent);
}
catch (IOException e)
{
  ...
}
finally
{
  try
  {
    response.getOutputStream().flush();
    response.getOutputStream().close();
  }
  catch (IOException e)
  {
    ...
  }
}

It must be a very simple failure but I cannot find it. Would be nice if you can help me with my problem. Thanks a lot in advance.

F4k3d
  • 653
  • 1
  • 10
  • 29

1 Answers1

22

You are converting the ByteArrayOutputStream to a byte[] before you have closed the ZipOutputStream. You must ensure zos is closed before you do baos.toByteArray(), the easiest way to ensure this is a try-with-resources construct:

  try
  {
    try (baos = new ByteArrayOutputStream();
         zos = new ZipOutputStream(baos))
    {
      for (RepBean rep : repsList)
      {
        String filename = rep.getFilename();
        ZipEntry entry = new ZipEntry(filename);
        entry.setSize(rep.getContent().length);
        zos.putNextEntry(entry);
        zos.write(rep.getContent());
        zos.closeEntry();
      }
    }
    // this is the zip file as byte[]
    reportContent = baos.toByteArray();
  }
  // catch blocks as before, finally is no longer required as the try-with-resources
  // will ensure the streams are closed
Ian Roberts
  • 120,891
  • 16
  • 170
  • 183
  • 1
    FYI, using the resource variables without declaring them at the same time only works in Java 9 or above. In Java 7 and 8 you can't reference variables in the try resources that are outside the block. In Java 7/8 you have to declare inline, like this post: https://stackoverflow.com/questions/23612864/create-a-zip-file-in-memory – MikeyT May 14 '19 at 14:46
  • I think that slightly more by-the-book approach is to call finish() on ZipOutputStream, because close() also closes the underlying stream which is referenced later. In this particular case (ByteArrayOutputStream) it does not matter but other stream classes might complain that they are used after close. – jacekbe Nov 14 '19 at 11:26
  • Helped me to fix my issue thanks, I was getting "There are some data after the end of the payload data :" error when trying to open the ZIP with 7zip, and windows couldnt decompress it, I missed the part (apparentlly super important) about `zos.close();` which was causing it! – JGlass Apr 20 '23 at 18:03