Java下载多个文件打成压缩包返回输出流,并解决被JVM占用无法打开

Posted 小花皮猪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java下载多个文件打成压缩包返回输出流,并解决被JVM占用无法打开相关的知识,希望对你有一定的参考价值。

需求

给前端提供一个接口,可下载文件,如果只是一个文件就直接返回输出流,如果多个就打成一个压缩包返回输出流

参考代码

代码根据自己的业务逻辑进行修改!

controller

/**
	 * 打包下载文档
	 * @param signId
	 */
	@PostMapping("/downloadZip")
	@ApiOperationSupport(order = 5)
	@ApiOperation(value = "下载文档", notes = "传入signId")
	public R download(@ApiParam(value = "签署id", required = true) @RequestParam Long signId) throws Exception 
		return R.data(signDocumentService.downloadZipFile(signId).toString());
	

service

	/**
	 * 根据id查询签署附件打包并下载
	 *
	 * @param signId
	 * @return FileOutputStream
	 * @throws Exception
	 */
	FileOutputStream downloadZipFile(Long signId) throws Exception;

serviceImpl

 @Override
    public FileOutputStream downloadZipFile(Long signId) throws Exception 
        InputStream input = null;
        //  定义压缩输出流
        ZipOutputStream zipOut = null;
        File zipFile = null;
        List<String> ossList = null;
        String path = null;
        String download = null;
        String localPath = null;
        try 
            ossList = new ArrayList();
            // 根据signId查询签署文档
            List<SignDocumentVO> signDocuments = signDocumentMapper.selectAttachs(signId);
            // 如果不为空
            if (!signDocuments.isEmpty()) 
                // 如果只有一个签署文件就直接下载,如果有多个就打压缩包
                if (signDocuments.size()==FILE_ONE.getCode()) 
                    return downloadDetails(signId);
                else
                    for (SignDocument signDocument : signDocuments) 
                        // 根据签署文档的attachId查询对应的附件
                        Attach attach = attachMapper.selectAttachById(signDocument.getAttachId());
                        String link = attach.getLink();
                        // 把oss文件下载到项目本地
                        path = SignDocumentServiceImpl.class.getClass().getResource("/").getPath() +
                                FileUtil.getNameWithoutExtension(link) + "." + PDF;
                        localPath = SignDocumentServiceImpl.class.getClass().getResource("/").getPath();
                        // 把获取到的oss文件链接下载到本地
                        download = download(link, path);
                        ossList.add(download);
                        //  定义压缩文件夹的名称和相关的位置
                        zipFile = new File(localPath + "file.zip");
                        //  实例化压缩输出流  并定制压缩文件的输出路径
                        zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
                    
                
            
            for (String o : ossList) 
                File file = new File(o);
                //  定义输入文件流
                input = new FileInputStream(file);
                // 一个文件对对应一个ZipEntry实体
                zipOut.putNextEntry(new ZipEntry(file.getName()));
                int readsize = 1024 * 1024 * 5;
                byte[] buf = new byte[readsize];
                int temp = 0;
                while ((temp = input.read(buf)) != -1) 
                    zipOut.write(buf, 0, temp);
                
            
            //  删除本地文件
           // FileUtil.deleteQuietly(new File(path));
         catch (IOException e) 
            log.error("打包下载失败!", e);
         finally 
            if(null != zipOut)
                zipOut.closeEntry();
                zipOut.close();
            
            if(null != input)
                input.close();
            
            // 回收资源
            System.gc();
        
        // 压缩包文件转为FileOutputStream
        FileOutputStream fileOutputStream = new FileOutputStream(String.valueOf(zipOut));
        return fileOutputStream;
    


    private FileOutputStream downloadDetails(Long signId) throws Exception 
        String path = null;
        String download = null;
        FileOutputStream fileOutputStream = null;
        // 根据signId查询签署文档
        List<SignDocumentVO> signDocuments = signDocumentMapper.selectAttachs(signId);
        // 如果不为空
        if (!signDocuments.isEmpty()) 
            for (SignDocument signDocument : signDocuments) 
                // 根据签署文档的attachId查询对应的附件
                Attach attach = attachMapper.selectAttachById(signDocument.getAttachId());
                String link = attach.getLink();
                // 把oss文件下载到项目本地
                path = SignDocumentServiceImpl.class.getClass().getResource("/").getPath() +
                FileUtil.getNameWithoutExtension(link) + "." + PDF;
                // 把获取到的oss文件链接下载到本地
                download = download(link, path);
                File file = new File(download);
                fileOutputStream = new FileOutputStream(file);
            
        
        return fileOutputStream;
    

调试效果


解压缩

解决文件被JVM占用无法打开

如果遇到这种错误

排查代码发现,流都关了,还是会出现这个问题,只能强制使用gc了

以上是关于Java下载多个文件打成压缩包返回输出流,并解决被JVM占用无法打开的主要内容,如果未能解决你的问题,请参考以下文章

如何将一个Java项目打包打成多个Jar包

Java 批量文件压缩导出,并下载到本地

多个java文件编译并打成jar包经典方法

JAVA输入/输出流程序例题(文件和目录字节流字符流)

如何把扫描的几个文件打成一个包?

怎么把多个文档合并成压缩包