I use three servlets to serve files for download:
- ByteArrayDownloadServlet: used for small files, such as reports or files from database
- FileDownloadServlet: used for small to large files
- MultipleFileDownloadServlet: create a zip with the requested files and stream it
They are based in the following implementation: link text
I have received several complaints about corrupted downloads. The problem is that I can't simulate or find a pattern in the errors:
- sometimes with large files
- sometimes when the user requests more than one file to download and a zip file and is created dynamically
- sometimes with smaller files, but that are being requested by many users simultaneously
In the post's mentioned above comments there are people reporting similar problems, but no solution. I also read a lot of threads from here and this the closer I got: link text
Has anyone went through similar problem or have some sample code that works?
Thanks, Felipe
@Override
@SuppressWarnings("unchecked")
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws Serv开发者_StackOverflow中文版letException, IOException
{
HttpSession session = request.getSession();
List<File> selectedFileList = (List<File>) session.getAttribute("selectedFileList");
if(selectedFileList == null)
{
response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED, "Lista de arquivos não informada");
return;
}
response.reset();
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=\""
+ "atualizacoes_"
+ new Date().getTime() + ".zip" + "\"");
ZipOutputStream output = null;
try
{
output = new ZipOutputStream(response.getOutputStream());
for(File file : selectedFileList)
{
InputStream input = new FileInputStream(file);
output.putNextEntry(new ZipEntry(file.getName()));
byte[] buffer = new byte[DownloadHandler.DEFAULT_BUFFER_SIZE];
int length;
while((length = input.read(buffer)) > 0)
{
output.write(buffer, 0, length);
}
output.closeEntry();
input.close();
}
output.finish();
output.flush();
output.close();
}
catch(Exception e)
{
if(!(e instanceof ClientAbortException))
{
new ExceptionMail(getClass().getSimpleName(), e);
}
}
finally
{
session.removeAttribute("selectedFileList");
}
The most common causes for randomly corrupted downloads from a servlet is that the servlet is not threadsafe and/or that it is reading bytes as characters. Sharing request or session based data among requests in the same session or servletcontext is also a possible cause for this problem.
You should not close the outputstream as it is managed by the servlet container. I'm not sure about the flush.
You have a serious flow in your code in below lines.
int length;
while((length = input.read(buffer)) > 0)
{
output.write(buffer, 0, length);
}
Your 'input' is a FileInputStream right? How can you make sure the FileInputStream has always more than 0 bytes available throughout your iteration? Instead above it must be written as below.
int length;
while((length = input.read(buffer)) != -1)
{
output.write(buffer, 0, length);
}
精彩评论