如何使用Liferay下载大文件(GB)时修复错误“Java堆空间”

时间:2017-05-24 22:27:47

标签: java download liferay httprequest

我使用此代码将Liferay(6.2)上的服务器上的现有文件下载到本地PC:

`

    File file = getFile(diskImage.getImageType(), diskImage.getId());

    HttpServletRequest httpReq = PortalUtil.getHttpServletRequest(request);
    HttpServletResponse httpResp = PortalUtil.getHttpServletResponse(response);

    httpResp.setContentType("application/octet-stream");
    httpResp.setHeader("Content-Transfer-Encoding", "binary");
    httpResp.setHeader("Content-Length", String.valueOf(file.length()));
    httpResp.setHeader("Content-Disposition", "attachment; filename=" + file.getName());

    try (InputStream input = new FileInputStream(file)) {
        ServletResponseUtil.sendFile(httpReq, httpResp, file.getName(), input, "application/octet-stream");
    } catch (Exception e) {
        throw new FilesManagerException(e);
    }
}

`

此代码仅适用于小文件。但是下载大文件(cca 2GB)会抛出javax.portlet.PortletException: Error occurred during request processing: Java heap space

如何修复此代码以使其适用于较大的文件? 我想合适的方法是使用某种缓冲区来处理大文件,我尝试一下,但即使对于较小的文件也不行。

3 个答案:

答案 0 :(得分:1)

首先:我假设你在渲染方法中这样做 - 这是完全错误的。迟早会破坏,因为您无法控制输出流:它可能已经提交并在您的portlet开始渲染时将数据传输到浏览器。在渲染中,您始终必须生成portlet的HTML代码。

相反,您应该转到portlet的资源服务阶段。使用ResourceRequestResourceResponse,您可以像使用HttpServletResponse一样支持设置mimetypes。

正是出于这个原因,ServletResponseUtil确实是一个错误的地方。如果你使用Liferay中的任何内容,你应该寻找PortletResponseUtil。有各种sendFile方法接受byte[],其他方法接受流或文件。我建议尝试这些,如果它们仍然失败,请查看最终的实现。在最坏的情况下,只是不要使用任何Util方法。将内容从一个流复制到另一个流并不是太糟糕。 (实际上,你不会在问题中给出变量input的静态类型的线索:如果那是byte[],那就是你的解决方案)

你可能想要向Liferay提出一个问题,如果纯粹的流传输确实将整个文件读入内存,但你的quickfix(如果这确实是一个bug)就是自己复制数据。

答案 1 :(得分:0)

感谢您的想法,最后我使用了PortletResponseUtil.sendFile(...);方法并将actionURL更改为responseURL文件中的.jsp。所以我用上面提到的方法实现了serveResource()。似乎一切都运转良好。

答案 2 :(得分:-1)

  

ServletResponseUtil.sendFile(httpReq,httpResp,file.getName(),input,“application / octet-stream”);这是什么?

不要一次读取文件。使用缓冲区。

response.reset();
response.setContentType("application/x-download");
response.addHeader("Content-Disposition","attachment;filename="+new String(filename.getBytes(),"utf-8"));
response.addHeader("Content-Length",""+file.length());
OutputStream toClient=new BufferedOutputStream(response.getOutputStream());
response.setContentType("application/octet-stream");
byte[] buffer=new byte[1024*1024*4];
int i=-1;
while((i=fis.read(buffer))!=-1){
  toClient.write(buffer,0,i);
}
fis.close();
toClient.flush();
toClient.close();