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

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,恶意文件检测 1000次 1年
对象存储 OSS,内容安全 1000次 1年
简介: Java下载多个文件打成压缩包返回输出流,并解决被JVM占用无法打开

需求


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


参考代码


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


controller

```java
/**
   * 打包下载文档
   * @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;
    }

调试效果

image.png

image.png

解压缩之后

image.png

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

image.png


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

image.png

相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
目录
相关文章
|
2月前
|
Java
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
84 9
|
2月前
|
监控 算法 Java
Java虚拟机(JVM)的垃圾回收机制深度解析####
本文深入探讨了Java虚拟机(JVM)的垃圾回收机制,旨在揭示其背后的工作原理与优化策略。我们将从垃圾回收的基本概念入手,逐步剖析标记-清除、复制算法、标记-整理等主流垃圾回收算法的原理与实现细节。通过对比不同算法的优缺点及适用场景,为开发者提供优化Java应用性能与内存管理的实践指南。 ####
|
1月前
|
监控 算法 Java
Java虚拟机(JVM)垃圾回收机制深度剖析与优化策略####
本文作为一篇技术性文章,深入探讨了Java虚拟机(JVM)中垃圾回收的工作原理,详细分析了标记-清除、复制算法、标记-压缩及分代收集等主流垃圾回收算法的特点和适用场景。通过实际案例,展示了不同GC(Garbage Collector)算法在应用中的表现差异,并针对大型应用提出了一系列优化策略,包括选择合适的GC算法、调整堆内存大小、并行与并发GC调优等,旨在帮助开发者更好地理解和优化Java应用的性能。 ####
42 0
|
7天前
|
人工智能 自然语言处理 Java
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
FastExcel 是一款基于 Java 的高性能 Excel 处理工具,专注于优化大规模数据处理,提供简洁易用的 API 和流式操作能力,支持从 EasyExcel 无缝迁移。
57 9
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
|
28天前
|
Java
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
86 34
|
1月前
|
存储 监控 算法
深入探索Java虚拟机(JVM)的内存管理机制
本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。
|
1月前
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
2月前
|
机器学习/深度学习 监控 算法
Java虚拟机(JVM)的垃圾回收机制深度剖析####
本文深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法、性能调优策略及未来趋势。通过实例解析,为开发者提供优化Java应用性能的思路与方法。 ####
56 1
|
2月前
|
Oracle 安全 Java
深入理解Java生态:JDK与JVM的区分与协作
Java作为一种广泛使用的编程语言,其生态中有两个核心组件:JDK(Java Development Kit)和JVM(Java Virtual Machine)。本文将深入探讨这两个组件的区别、联系以及它们在Java开发和运行中的作用。
106 1
|
2月前
|
监控 Java 开发者
Java虚拟机(JVM)深度优化指南####
本文深入探讨了Java虚拟机(JVM)的工作原理及其性能优化策略,旨在帮助开发者通过理解JVM的内部机制来提升Java应用的运行效率。不同于传统的技术教程,本文采用案例分析与实战技巧相结合的方式,为读者揭示JVM调优的艺术。 ####
59 8