首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring,Java :流文件下载以避免内存不足

Spring,Java :流文件下载以避免内存不足
EN

Stack Overflow用户
提问于 2016-05-12 08:42:16
回答 1查看 6.7K关注 0票数 2

我正在开发一个Spring应用程序,用户可以在这个应用程序中下载文件。用户可以单击触发下载机制的附件。

昨天,当多次下载(其中两个下载大约有2GB文件)时,它导致内存不足错误(日志如下)。

为了避免此问题,解决此问题的一种方法似乎是将下载数据以块形式流,并且只处理服务层中的这些块,而不是整个文件。

不幸的是,我不知道该怎么做,任何帮助都会很好。如果这个选项不能运行,任何关于如何解决这个问题的建议。

错误日志:

代码语言:javascript
复制
HTTP Status 500 - Handler processing failed; nested exception is java.lang.OutOfMemoryError: Direct buffer memory

type Exception report

message Handler processing failed; nested exception is java.lang.OutOfMemoryError: Direct buffer memory

description The server encountered an internal error that prevented it from fulfilling this request.

exception

org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.OutOfMemoryError: Direct buffer memory
    org.springframework.web.servlet.DispatcherServlet.triggerAfterCompletionWithError(DispatcherServlet.java:1303)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:977)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:858)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843)

控制器代码:

代码语言:javascript
复制
    @RequestMapping(value = "/download/attachment/{attachid}", method = RequestMethod.GET)
        public void getAttachmentFromDatabase(@PathVariable("attachid") int attachid,
    , HttpServletResponse response,) {

response.setContentType("application/octet-stream");
GroupAttachments groupAttachments = this.groupAttachmentsService.getAttachmenById(attachid);
response.setHeader("Content-Disposition", "attachment; filename=\"" + groupAttachments.getFileName() + "\"");
                            response.setContentLength(groupAttachments.getSendAttachment().length);
                            FileCopyUtils.copy(groupAttachments.getSendAttachment(), response.getOutputStream());
    response.flushBuffer();

    }

服务层:

代码语言:javascript
复制
@Override
    public GroupAttachments getAttachmenById(int attachId) {
        Person person = this.personService.getCurrentlyAuthenticatedUser();
        GroupAttachments groupAttachments = this.groupAttachmentsDAO.getAttachmenById(attachId);

        GroupMembers groupMembers = this.groupMembersService.returnMembersMatchingUsernameAccountId(person.getUsername(),
                groupAttachments.getGroupId());
        if (!(groupMembers == null)) {
            if (person.getUsername().equals(groupMembers.getMemberUsername())) {
                try {
                    Path path = Paths.get(msg + groupAttachments.getGroupId() + "/" +
                            groupAttachments.getFileIdentifier());
                    groupAttachments.setSendAttachment(Files.readAllBytes(path));
                    return groupAttachments;
                } catch (IOException ignored) {
                    this.groupAttachmentsDAO.removeAttachment(attachId);
                    return null;
                }
            }
            return null;
        } else {
            return null;
        }
    }

谢谢。:-)

更新

新下载机制:

主计长:

代码语言:javascript
复制
 public ResponseEntity<byte[]> getAttachmentFromDatabase(@PathVariable("attachid") int attachid,
                                                    @PathVariable("groupaccountid") Long groupAccountId, @PathVariable("api") String api,
                                                    HttpServletResponse response,
                                                    @PathVariable("type") boolean type) {

 Path path = this.groupAttachmentsService.getAttachmentPathById(attachid);

        GroupAttachments groupAttachments = this.groupAttachmentsService.getAttachmentObjectOnlyById(attachid);
                        response.setContentType("application/octet-stream");
                        response.setHeader("Content-Disposition", "attachment; filename=\""+groupAttachments.getFileName()+"\"");
  try {
OutputStream outputStream = response.getOutputStream();

Files.copy(path,outputStream);
outputStream.flush();
outputStream.close();
response.flushBuffer();
}

服务层:

代码语言:javascript
复制
@Override
    public Path getAttachmentPathById(int attachId){
        Person person = this.personService.getCurrentlyAuthenticatedUser();
        GroupAttachments groupAttachments = this.groupAttachmentsDAO.getAttachmenById(attachId);

        GroupMembers groupMembers = this.groupMembersService.returnMembersMatchingUsernameAccountId(person.getUsername(),
                groupAttachments.getGroupId());
        if (!(groupMembers == null)) {
            if (person.getUsername().equals(groupMembers.getMemberUsername())) {
                try {
                    return Paths.get(msg + groupAttachments.getGroupId() + "/" +
                            groupAttachments.getFileIdentifier());
                } catch (Exception ignored) {
                    return null;
                }
            }
            return null;
        } else {
            return null;
        }
    }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-05-12 09:14:49

首先,停止在服务中加载整个内容,因为在那里,您要将大量文件内容加载到内存中。

创建一个为Path构造GroupAttachments的方法,我将在GroupAttachments it self上创建这个方法。

代码语言:javascript
复制
public class GroupAttachments {

    public Path getPath() {
        return Paths.get(msg + getGroupId() + "/" + getFileIdentifier());
    }
}

然后在你的控制器里简单地做

代码语言:javascript
复制
@RequestMapping(value = "/download/attachment/{attachid}", method = RequestMethod.GET)
public void getAttachmentFromDatabase(@PathVariable("attachid") int attachid, HttpServletResponse response) {

  response.setContentType("application/octet-stream");
  GroupAttachments groupAttachments = this.groupAttachmentsService.getAttachmenById(attachid);
  Path path = groupAttachmetns.getPath(); // calculates the java.nio.file.Path  
  response.setHeader("Content-Disposition", "attachment; filename=\"" + path.getFileName() + "\"");
  response.setContentLength(Files.size(path);
  Files.copy(path, response.getOutputStream());
  response.flushBuffer();

}

没有必要让它变得更加复杂。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37181640

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档