Quote of the Day

more Quotes

Categories

Buy me a coffee

  • Home>
  • Java>

The file is damaged and could not be repaired.

Published October 31, 2020 in Java - 0 Comments

I want to share this familiar but cryptic error I experienced when opening certain PDFs which were streamed from a Java web application.

PDF corrupted message

We were a bit puzzled by the error because although those PDF files appeared broken in Adobe Reader, we were able to open them just fine in Chrome PDF viewer. Furthermore, we only got the error for certain PDF images. Adobe Reader was able to render other images that we streamed from the same app just fine.

It turned out the error was because in the java application, we were dumping the content to the output stream all at once, without including the ‘Content-Length’ header. Below snippets show the simplified part of the codes before applying the fix.

        OutputStream out = null;
        response.setContentType("application/pdf");
        try {
            out = response.getOutputStream();
            out.write(documentBean.getDocumentContentBytes());
        } finally {
            if (out != null) {
                out.flush();
                out.close();
            }
        }

As you can see, the above codes grab the HTTP output stream and write all the bytes at once. However, it does not include the ‘Content-Length’ header.

So, don’t forget the ‘Content-Length’ header when returning PDF content to the browser.

        OutputStream out = null;
        response.setContentType("application/pdf");
        response.setContentLength(documentBean.getDocumentContentBytes().length);
        try {
            out = response.getOutputStream();
            out.write(documentBean.getDocumentContentBytes());
        } finally {
            if (out != null) {
                out.flush();
                out.close();
            }
        }

Another way to avoid corrupting the PDF files is to use a buffer. In our case, we made changes to use both the buffer and also include the header, since we already know the content length from the bytes.

response.setContentType(documentBean.getMimeType());
response.setContentLength(documentBean.getDocumentContentBytes().length);
try (InputStream docImage = new BufferedInputStream(new ByteArrayInputStream(documentBean.getDocumentContentBytes())); OutputStream outStream = response.getOutputStream()) {
    byte[] readingBuffer = new byte[100 * 1024];
    int read = 0;
    while ((read = docImage.read(readingBuffer, 0, readingBuffer.length)) !=
        -1) {
        outStream.write(readingBuffer, 0, read);
        outStream.flush();
    }
} catch (IOException ex) {
    logger.error("An error occurred while writing document image to stream.", ex);
}

That’s it for this post.

No comments yet