我使用此代码将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
。
如何修复此代码以使其适用于较大的文件? 我想合适的方法是使用某种缓冲区来处理大文件,我尝试一下,但即使对于较小的文件也不行。
答案 0 :(得分:1)
首先:我假设你在渲染方法中这样做 - 这是完全错误的。迟早会破坏,因为您无法控制输出流:它可能已经提交并在您的portlet开始渲染时将数据传输到浏览器。在渲染中,您始终必须生成portlet的HTML代码。
相反,您应该转到portlet的资源服务阶段。使用ResourceRequest
和ResourceResponse
,您可以像使用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();