2010-10-04 39 views
0

我用三個servlet來提供文件下載:的Java servlet:問題與損壞的文件下載

  • ByteArrayDownloadServlet:用於小文件,如
  • FileDownloadServlet從數據庫報告或文件:用於小大文件
  • MultipleFileDownloadServlet:創建請求文件的zip和流它

他們根據以下實現: link text

我所收到的有關損壞下載多次投訴。問題是,我不能模擬或發現在錯誤的模式:

    有時
  • 大文件
  • 有時當用戶請求一個以上的文件下載和zip文件,並動態創建
  • 有時
  • 較小的文件,但正在被許多用戶要求同時

在上面提到的意見都有人報告類似的問題這篇文章的,但沒有解決方案。我也讀了很多來自這裏的線索和這個我得到更近: link text

有沒有人經歷過類似的問題或有一些示例代碼的作品?

謝謝, 菲利普

@Override 
@SuppressWarnings("unchecked")  
protected void doGet(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, 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");   
    } 
+1

你終於發現BalusC:http://stackoverflow.com/users/157882/balusc – 2010-10-04 13:19:36

+1

'FileServlet'你改變對原來的什麼?沒有一些代碼或其他細節,很難確切地知道發生了什麼問題。 – 2010-10-04 14:34:56

回答

2

用於從一個servlet隨機損壞的下載內容的最常見的原因是,該servlet不是線程和/或它被讀取字節爲字符。在同一會話或servletcontext中的請求之間共享請求或基於會話的數據也是導致此問題的一個原因。

+0

你能給這個信息? 謝謝 – FkJ 2010-10-07 18:44:26

+0

當servlet將請求或會話作用域數據分配爲方法塊中使用的servlet實例變量時,它不是線程安全的。流式傳輸字節不應該使用'Reader'或'Writer'完成。 – BalusC 2010-10-07 18:56:02

+0

我附上了我的多個文件下載servlet。我不使用實例變量。我錯過了什麼嗎? 謝謝 – FkJ 2010-10-07 20:11:31

0

,因爲它是由servlet容器管理你不應該關閉的OutputStream。 我不清楚沖水。

+0

它不會導致損壞的下載。相關:http://stackoverflow.com/questions/1829784/should-i-close-the-servlet-outputstream/1829823#1829823 – BalusC 2012-12-24 13:13:43

+0

是的,但它是一個不好的實踐。你也應該定義內容長度標題到你的迴應 – ehsavoie 2012-12-31 14:34:22

+0

這只是你自己的代碼做到了。仔細閱讀給定的鏈接。 – BalusC 2012-12-31 14:35:07

0

您有以下行代碼中的一個嚴重的流動。

int length; 
     while((length = input.read(buffer)) > 0) 
     { 
      output.write(buffer, 0, length); 
     } 

你的'輸入'是一個FileInputStream嗎?你如何確保FileInputStream在你的迭代中總是有超過0個字節可用?取而代之的是它必須寫成如下。

int length; 
     while((length = input.read(buffer)) != -1) 
     { 
      output.write(buffer, 0, length); 
     }