Spring REST - 正在下载损坏/空白文件

Posted

技术标签:

【中文标题】Spring REST - 正在下载损坏/空白文件【英文标题】:Spring REST - Damaged/Blank File being downloaded 【发布时间】:2018-10-07 03:20:28 【问题描述】:

我正在尝试创建一个端点来呈现/提供 PDF 文件。 我已通过以下链接构建 API,但仍面临一些问题。

link 1

link 2

以下是我的代码:

byte[] targetArray = null;

InputStream is = null;

InputStream objectData = object.getObjectContent();

BufferedReader reader = new BufferedReader(new InputStreamReader(objectData));

char[] charArray = new char[8 * 1024];
StringBuilder builder = new StringBuilder();
int numCharsRead;
while ((numCharsRead = reader.read(charArray, 0, charArray.length)) != -1) 

    builder.append(charArray, 0, numCharsRead);

reader.close();

objectData.close();
object.close();
targetArray = builder.toString().getBytes();

is = new ByteArrayInputStream(targetArray);


return ResponseEntity.ok().contentLength(targetArray.length).contentType(MediaType.APPLICATION_PDF)
                .cacheControl(CacheControl.noCache()).header("Content-Disposition", "attachment; filename=" + "testing.pdf")
                .body(new InputStreamResource(is));

当我使用邮递员访问我的 API 时,我可以下载 PDF 文件,但问题是它完全是空白的。可能是什么问题?

【问题讨论】:

嗯...为什么要将PDF读入char的数组,将其转换为String,然后从字符串中提取字节?你明白字符数据和二进制数据的区别吧? 另外,既然您的数据已经有一个InputStream,为什么不使用您提到的第一个链接中的InputStreamResource 实际上我正在尝试从远程位置获取 PDF 文件的内容,该位置正在流式传输我的 PDF 文件内容。 很公平,但是由于您使用InputStream 对其进行操作,因此对您来说应该是透明的。当您直接返回 InputStreamResource 包装 objectData 时会发生什么?为什么你觉得你需要所有的中间步骤? 其实InputStream是S3ObjectInputStream 【参考方案1】:

从服务器下载文件有多种方式,您可以使用ResponseEntity<InputStreamResource>HttpServletResponse。以下是两种下载方式。

@GetMapping("/download1")
       public ResponseEntity<InputStreamResource> downloadFile1() throws IOException 

          File file = new File(FILE_PATH);
          InputStreamResource resource = new InputStreamResource(new FileInputStream(file));

          return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION,
                      "attachment;filename=" + file.getName())
                .contentType(MediaType.APPLICATION_PDF).contentLength(file.length())
                .body(resource);
       

您可以使用StreamingResponseBody 下载文件。在这种情况下,服务器将数据写入OutputStream,同时浏览器读取数据,这意味着它是并行的。

@RequestMapping(value = "downloadFile", method = RequestMethod.GET)
    public StreamingResponseBody getSteamingFile(HttpServletResponse response) throws IOException 
        response.setContentType("application/pdf");
        response.setHeader("Content-Disposition", "attachment; filename=\"demo.pdf\"");
        InputStream inputStream = new FileInputStream(new File("C:\\demo-file.pdf"));
        return outputStream -> 
            int nRead;
            byte[] data = new byte[1024];
            while ((nRead = inputStream.read(data, 0, data.length)) != -1) 
                System.out.println("Writing some bytes..");
                outputStream.write(data, 0, nRead);
            
        ;
    

【讨论】:

【参考方案2】:

你可以尝试使用apache commons IOUtils。为什么要重新发明***:) 1.打开与远程服务器的连接 2.将inputStream复制到目标文件outputStream。

public void downloadFileFromRemoteLocation(String serverlocation, File destinationFile) throws IOException

    try (FileOutputStream fos = new FileOutputStream( destinationFile ))
        URL url = new URL(serverlocation);
        URLConnection connection = url.openConnection();
        IOUtils.copy( connection.getInputStream(),  fos);
     

如果您只想坚持 Java,请查看下面的 sn-p

try 
        // Get the directory and iterate them to get file by file...
        File file = new File(fileName);

        if (!file.exists()) 
            context.addMessage(new ErrorMessage("msg.file.notdownloaded"));
            context.setForwardName("failure");
         else 
            response.setContentType("APPLICATION/DOWNLOAD");
            response.setHeader("Content-Disposition", "attachment"+ 
                                     "filename=" + file.getName());
            stream = new FileInputStream(file);
            response.setContentLength(stream.available());
            OutputStream os = response.getOutputStream();      
            os.close();
            response.flushBuffer();
        
     catch (IOException e) 
        e.printStackTrace();
     finally 
        if (stream != null) 
            try 
                stream.close();
             catch (IOException e) 
                e.printStackTrace();
            
        
    

【讨论】:

以上是关于Spring REST - 正在下载损坏/空白文件的主要内容,如果未能解决你的问题,请参考以下文章

从 Spring Boot Rest 服务下载文件

下载xlsx文件打开一直提示文件已损坏

通过 REST API 上传多部分文件会损坏文件并增加文件大小

使用 REST API 上传到 Azure Blob 存储时,Zip 档案损坏

Spring Boot Rest 服务下载包含多个文件的 zip 文件

如何使用 spring rest 服务/spring boot 下载 Excel