2011-08-18 115 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配置),或存储器正在别处泄漏。