如何使用angular.js和java使用大文件逐块下载大文件

时间:2018-08-07 11:35:36

标签: java angularjs blob download-manager

我们有一个Web应用程序,其中agnular.js中的客户端和java spring中的服务器。我正在研究从客户端下载此日志文件(即logs.tar)的功能。

当前,我们正在使用blob下载。我们的问题是,如果此日志大小变得很大(如大于2GB),则在流式传输时会在应用程序内存上造成负载。所以我想要一种方法来逐块下载大文件,而不需要将整个Blob加载到内存中。请建议出路。

服务器端Java代码-

   public ResponseEntity<?> downloadLogs(HttpServletRequest request) {
        File file = preferencesService.downloadLogs();
        if (file != null) {
            FileInputStream inputStream;
            try {
                inputStream = new FileInputStream(file);
                byte[] content = FileCopyUtils.copyToByteArray(inputStream);

                String filename = "com-logs.tar";
                HttpHeaders responseHeaders = new HttpHeaders();
                responseHeaders.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename);
                responseHeaders.add(HttpHeaders.CONTENT_TYPE, "application/octet-stream"

);

        return new ResponseEntity<byte[]>(content, responseHeaders, HttpStatus.OK);

        } catch (Exception e) {
            logger.error("Error while processing log file for download", e);
        }
    } else {
        logger.error("Failed to download logs");
    }
    return ResponseEntity.badRequest().build();
} 

客户端Angular.js代码-

this._service.downloadLogs().subscribe(
            success => {               
                var blb = new Blob([success], { 'type': "application/octet-stream" });
                if (window.navigator && window.navigator.msSaveOrOpenBlob) {
                    window.navigator.msSaveOrOpenBlob(blb, 'logs.tar');
                }
                else {
                    var link = document.createElement('a');
                    link.href = window.URL.createObjectURL(blb);
                    link.download = "logs.tar";
                    document.body.appendChild(link);
                    link.click();
                    document.body.removeChild(link);
                }
            });

新服务器端Java代码-

public void downloadLogs(HttpServletResponse resonse) {
        File file = preferencesService.downloadLogs(id);       
        if (file != null) {
            try {
                resonse.setContentType("application/octet-stream");
                resonse.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
                BufferedInputStream inStrem = new BufferedInputStream(new FileInputStream(file));
                BufferedOutputStream outStream = new BufferedOutputStream(resonse.getOutputStream());

                byte[] buffer = new byte[1024];
                int bytesRead = 0;
                while ((bytesRead = inStrem.read(buffer)) != -1) {
                    outStream.write(buffer, 0, bytesRead);
                }
                outStream.flush();
                inStrem.close();

            } 
            ...
        }

1 个答案:

答案 0 :(得分:2)

重要的是不要将文件读入内存,而是将流传递给:

public ResponseEntity<?> downloadLogs(HttpServletRequest request) {
    File file = preferencesService.downloadLogs();
    if (file != null) {
        try (InputStream inputStream = Files.newInputStream(file.toPath())) {
            InputStreamResource inputStreamResource =
                    new InputStreamResource(new inputStream);
            HttpHeaders responseHeaders = new HttpHeaders();
            //responseHeaders.setContentLength(Files.size(file.toPath()));
            responseHeaders.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="
                    + filename);
            responseHeaders.add(HttpHeaders.CONTENT_TYPE, "application/octet-stream");
            return new ResponseEntity(inputStreamResource, responseHeaders, HttpStatus.OK);
        }
    }
    ...
}

考虑压缩,因为这将大大加快处理速度并减少服务器负载。 应研究分块,设置内容长度,压缩压缩W​​eb过滤器等。