2011-08-18 120 views
13

當我試圖下載一個大文件是從服務器260MB的,我得到這個錯誤:java.lang.OutOfMemoryError: Java heap space.我相信我的堆大小小於252MB。有什麼辦法可以在不增加堆大小的情況下下載大文件?如何下載大文件時內存問題在Java

如何下載大文件沒有得到這個問題?我的代碼如下:

String path= "C:/temp.zip"; 
response.addHeader("Content-Disposition", "attachment; filename=\"test.zip\""); 
byte[] buf = new byte[1024]; 
try { 

      File file = new File(path); 
      long length = file.length(); 
      BufferedInputStream in = new BufferedInputStream(new FileInputStream(file)); 
      ServletOutputStream out = response.getOutputStream(); 

      while ((in != null) && ((length = in.read(buf)) != -1)) { 
      out.write(buf, 0, (int) length); 
      } 
      in.close(); 
      out.close(); 
+0

您能夠增加對JVM堆大小?即:JAVA -Xm512m -Xmx512m MyClass的 –

+0

是的,但我想,要知道如果我能做到這一點不增加JVM堆大小,因爲我們有一個要求,以約1GB的大容量文件下載到10 GB –

回答

16

有2個地方,我可以看到你有可能被建立內存使用:

  1. 在緩衝區中讀取輸入文件。
  2. 在緩衝區寫入到您的輸出流(HTTPOutputStream?)

#1我建議從文件通過FileInputStream沒有BufferedInputStream直接讀取。先試試看看它是否能解決你的問題。即:

FileInputStream in = new FileInputStream(file); 

代替:

BufferedInputStream in = new BufferedInputStream(new FileInputStream(file)); 

如果#1不能解決問題,你可以(如果需要減少塊大小)嘗試定期經過這麼多的數據被寫入刷新輸出流:

即:

try 
{ 
    FileInputStream fileInputStream = new FileInputStream(file); 
    byte[] buf=new byte[8192]; 
    int bytesread = 0, bytesBuffered = 0; 
    while((bytesread = fileInputStream.read(buf)) > -1) { 
     out.write(buf, 0, bytesread); 
     bytesBuffered += bytesread; 
     if (bytesBuffered > 1024 * 1024) { //flush after 1MB 
      bytesBuffered = 0; 
      out.flush(); 
     } 
    } 
} 
finally { 
    if (out != null) { 
     out.flush(); 
    } 
} 
+1

謝謝JJ這是工作 –

+2

上面的代碼有一個小問題。如果圍繞代碼或while循環結束的try-catch,我們需要在finally塊中添加一個更多的flush。否則它不會刷新完整的字節。否則可能會導致一些問題。 – Arundev

+1

@Arundev:公平點,我更新了上面的代碼。 –

4

不幸的是,您還沒有提及什麼類型的out是。如果你有內存問題,我想這是ByteArrayOutpoutStream。因此,將其替換爲FileOutputStream並將要直接下載的字節寫入文件。

BTW,不要使用read()方法讀取逐字節。改爲使用read(byte[] arr)。這要快得多。

+0

由「反應來判斷。 setContentType「和」response.setHeader「調用,這是一個servlet - 即。他將文件傳輸到Web客戶端,「out」是HttpOutputStream。 –

+0

謝謝亞歷克斯,但我的主要問題是下載可以1GB的文件較大,10 GB大小的文件。這裏我得到了內存異常。我該如何處理這不增加堆大小.... –

+0

OK,現在你已經更新了你的代碼,問題更加清晰。我認爲你的程序正在從遠程URL下載文件,但你提​​出了相反的問題:你的servlet提供了下載文件的能力。所以,我認爲你的問題在於你沒有在每次輸出之後調用out.flush()。write(),所以你正在讀取的所有字節都存儲在內存中,並且在關閉輸出流之前不會發送到網絡。嘗試刷新,看看發生了什麼。 – AlexR

0

首先,你可以從你的while語句刪除(在!= NULL),這是不必要的。其次,嘗試刪除的BufferedInputStream,只是做:

FileInputStream in = new FileInputStream(file); 
0

沒有錯(關於內存使用)的代碼是你表演。或者servlet容器被配置爲緩衝整個響應(看web.xml配置),或存儲器正在別處泄漏。