java将文件压缩打包后进行下载
今天受到一个需求,需要查出文件,然后将文件打包后下载。看了下项目里默认代码有压缩功能,以此修改了下,项目使用了hutool。项目是若依项目
定义zip的数据传输对象,ossId可以是文件表的id
@Data
public class SysOssZipDTO {/*** 关联OSS对象存储ID*/
})private String ossId;/*** 压缩包文件内文件夹路径,例子(main/java/com/haoyu/flowForm/domain/)*/private String zipItemFolderPath;}
sevice层
void downloadZip(List<SysOssZipDTO> zipDtoList, HttpServletResponse response, String taskId) throws IOException;
serviceImpl层
@Overridepublic void downloadZip(List<SysOssZipDTO> zipDtoList, HttpServletResponse response, String taskId) throws IOException {if(zipDtoList == null || zipDtoList.isEmpty()){return;}ZipOutputStream zip = new ZipOutputStream(response.getOutputStream());final int bufferSize = 1024 * 1024 * 5; // 5MBfinal byte[] buffer = new byte[bufferSize];long totalFileSize = 0; // 文件总大小,估计值// 任务进度keyfinal String progressKey = OssConstant.SYS_OSS_PROGRESS+taskId;for (int i =0;i<zipDtoList.size();i++){// 设置进度(可选,用于压缩进度查询,就是将进度存入redis里,然后设计个接口供前端查询进度)/*SysOssProgressBO sysOssProgressBO = new SysOssProgressBO();sysOssProgressBO.setProgressNumber(Long.valueOf(i));sysOssProgressBO.setTotalProgress(Long.valueOf(zipDtoList.size()));RedisUtils.setCacheObject(progressKey,sysOssProgressBO, Duration.ofMinutes(10));*/SysOssZipDTO zipDTO = zipDtoList.get(i);if(StrUtil.isEmpty(zipDTO.getOssId())|| StrUtil.isEmpty(zipDTO.getZipItemFolderPath())){continue;}// 通过id查找文件信息SysOssVo sysOss = matchingUrl(SpringUtils.getAopProxy(this).getById(zipDTO.getOssId()));if (ObjectUtil.isNull(sysOss)) {continue;}// 通过文件信息获取文件流,本文用的Oss存储,如果用别的可以自己写,核心就是读取流OssClient storage = OssFactory.instance(sysOss.getService());try(InputStream inputStream = storage.getObjectContent(sysOss.getUrl());){// 这里使用文件名了,拼上前缀序号解决文件名重复问题zip.putNextEntry(new ZipEntry(zipDTO.getZipItemFolderPath() +"("+i+")"+sysOss.getOriginalName().replaceAll("/","_" )));int available = inputStream.available();totalFileSize += available;// 防Oom,可以用下面注释的也可以用hutool的/*int len = 0;while((len = inputStream.read(buffer)) != -1){zip.write(buffer, 0, len);}*/IoUtil.copy(inputStream, zip, bufferSize);zip.flush();zip.closeEntry();}catch (Exception e) {throw new ServiceException(e.getMessage());}}IoUtil.close(zip);// 生成zip文件// 由于前面已经开启了response的outputstream,所以这里不能调用reset()方法,否则会导致流异常关闭
// response.reset();response.addHeader("Access-Control-Allow-Origin", "*");response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");response.addHeader("Content-Length", "" + totalFileSize);response.setContentType("application/octet-stream; charset=UTF-8");// 下载后的文件名可以由前端控制,此处由前端控制所以注释掉了/*if(StrUtil.isNotEmpty(zipName)){FileUtils.setAttachmentResponseHeader(response, zipName + ".zip");}*/}
其中的文件查询进度是可选的,可以让前端生成个任务id传到服务器
controller层
@GetMapping("/downloadZipByTrainId/{trainId}")public void downloadZipByTrainId(HttpServletResponse response, @PathVariable String trainId) throws IOException {// downloadZipByTrainId()方法里面调用downloadZip()this.iTrainMaterialsService.downloadZipByTrainId(trainId,response);}
前端代码,此处使用的是vue3
// 需要npm安装file-saver
import { saveAs } from 'file-saver'// 点击按钮触发事件
const clickDownLoadMaterials = async (row) =>{if(row.materialCount > 0 ){let res = await zip(`/train/trainMaterials/downloadZipByTrainId/${row.id}?projectName=${row.trainName}`,`${row.trainName}`)}else{ElMessage({message: '暂无材料可下载!',type: 'warning',})}
}const zip = (url, name) => {isShowLoadingDownLoadMaterial.value = trueurl = baseURL + urlaxios({method: 'get',url: url,responseType: 'blob',headers: {// 请求头token'Authorization': 'Bearer ' + getToken()}}).then(async (res) => {if(res.status == 200){isShowLoadingDownLoadMaterial.value = false}const isLogin = await blobValidate(res.data);if (isLogin) {const blob = new Blob([res.data], { type: 'application/zip' })saveAss(blob, name)} else {await this.printErrMsg(res.data);}})
}const saveAss = (text, name, opts) =>{saveAs(text, name, opts);
}// 验证是否为blob格式
export async function blobValidate(data) {try {const text = await data.text();JSON.parse(text);return false;} catch (error) {return true;}
}
杂谈
这次的需求整理到了不少东西,一开始担心oom的问题,于是调试时改变了缓冲区大小,发现java使用的内存也会对应的发生变化,这是为什么呢?实际上原因很简单,final byte[] buffer = new byte[bufferSize];这个变量就是占用这么多字节的内存呀!
当缓冲区设成0的时候,会发现读的特别特别慢,这是为什么呢?这是由于读的大小太小了,java调取磁盘io的频率变多,而调取磁盘io是一个特别消耗资源的行为也特别慢,因此就慢了。设置合适的缓冲区大小,可以一次性读取对应大小的内容从而减少磁盘io的交互从而提升效率,但也要避免缓冲区过大导致变量占用内存过大而oom。
同时,java流的操作不是一次性将整个文件都读入内存中的,而是仅仅获取文件的句柄,同时读偏移量,不停的读,移动偏移量,直至文件读写结束(大佬原话)。而且系统加载文件到内存也是按块加载的,并不会一次性全读到内存中(如一个几十g的游戏,打开并不会占用几十g内存,而是用到的时候在加载,不足的时候就会根据算法按页或者按块替换)
最后,开了流一定要关流!response.getOutputStream()自带的流可以不用手动关servlet在请求结束的时候会自己关掉
相关文章:
java将文件压缩打包后进行下载
今天受到一个需求,需要查出文件,然后将文件打包后下载。看了下项目里默认代码有压缩功能,以此修改了下,项目使用了hutool。项目是若依项目 定义zip的数据传输对象,ossId可以是文件表的id Data public class SysOssZi…...
【4/26-4/30】 Arxiv安全类文章速览
4/26 标题: Merchants of Vulnerabilities: How Bug Bounty Programs Benefit Software Vendors 作者: Esther Gal-Or, Muhammad Zia Hydari, Rahul Telang摘要: 软件漏洞允许恶意黑客利用,威胁系统和数据安全。本文研究了激励道德黑客发现并负责任地向软件供应商披…...
活动图与状态图:UML中流程图的精细化表达——专业解析系统动态性与状态变迁
流程图是一种通用的图形表示法,用以展示步骤、决策和循环等流程控制结构。它通常用于描述算法、程序执行流程或业务过程,关注于任务的顺序执行。流程图强调顺序、分支和循环,适用于详细说明具体的处理步骤,图形符号相对基础和通用…...
Easy TCP Analysis提供了四大特性,兼顾了TCP数据包分析入门学习到实战问题排查不同阶段用户对工具的需求
一款兼顾TCP数据包分析入门学习和实战不同阶段用户需求的工具 Easy TCP Analysis是一款在线TCP数据包分析工具,致力于让TCP数据包分析变得跟看聊天记录一样简单! Easy TCP Analysis提供了四大特性,兼顾了从入门学习到实战分析不同阶段用户对…...
【2】STM32·FreeRTOS·任务创建和删除
目录 一、任务创建和删除的API函数 1.1、动态创建任务函数 1.2、静态创建任务函数 1.3、任务删除函数 二、任务创建和删除(动态方法) 三、任务创建和删除(静态方法) 一、任务创建和删除的API函数 任务的创建和删除本质就是…...
日志审计系统在提高网络安全方面具有哪些重要的作用
随着信息技术的飞速发展,我们正处于一个高度互联、数据驱动的网络时代。在这个时代,日志审计系统作为网络安全和信息管理的重要工具,发挥着至关重要的作用。下面德迅云安全就详细介绍下关于日志审计系统在当今网络时代的重要性。 一、什么是日…...
二维泊松方程(Neumann+Direchliet边界条件)有限元Matlab编程求解|程序源码+说明文本
专栏导读 作者简介:工学博士,高级工程师,专注于工业软件算法研究本文已收录于专栏:《有限元编程从入门到精通》本专栏旨在提供 1.以案例的形式讲解各类有限元问题的程序实现,并提供所有案例完整源码;2.单元…...
13_Scala面向对象编程_伴生对象
文章目录 1.伴生对象1.1 scala的一个性质,scala文件中的类都是公共的;1.2 scala使用object关键字也可以声明对象; 3.关于伴生对象和类4.权限修饰符,scala仅有private;5.伴生对象可以访问伴生类中的私有属性;6.案例7.伴…...
RS485空调系统到BACnet江森楼宇系统的高效整合攻略
智慧城市的每一栋建筑都在追求更高的能效与更佳的居住体验,而这一切的实现离不开强大且灵活的楼宇自动化系统。其中,协议转换网关作为连接不同设备的纽带,扮演着至关重要的角色。本文将以一个典型的商业综合体为例,揭秘BACnet协议…...
Springboot集成Redis操作缓存-06
Redis简介 Redis(Remote Dictionary Server),即远程字典服务,是一个开源的、使用ANSI C语言编写的、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。 功能特点 数据结构丰富&#…...
【WPF】聊聊WPF中INotifyPropertyChanged [TOC]
聊聊WPF中INotifyPropertyChanged 文章目录 聊聊WPF中INotifyPropertyChanged一、INotifyPropertyChanged接口二、DataContext2.1/DataContext作用2.2/DataContext特性2.3/DataContext实例 三、INotifyPropertyChanged接口的几种实现方式3.1/简单INotifyPropertyChanged绑定3.2…...
SpringBoot Actuator未授权访问漏洞的解决方法
1. 介绍 Spring Boot Actuator 是一个用于监控和管理 Spring Boot 应用程序的功能模块。它提供了一系列生产就绪的功能,帮助你了解应用程序的运行状况,以及在运行时对应用程序进行调整。Actuator 使用了 Spring MVC 来暴露各种 HTTP 或 JMX 端点&#x…...
AI大模型探索之路-训练篇18:大语言模型预训练-微调技术之Prompt Tuning
系列篇章💥 AI大模型探索之路-训练篇1:大语言模型微调基础认知 AI大模型探索之路-训练篇2:大语言模型预训练基础认知 AI大模型探索之路-训练篇3:大语言模型全景解读 AI大模型探索之路-训练篇4:大语言模型训练数据集概…...
Ollamallama
Olllama 直接下载ollama程序,安装后可在cmd里直接运行大模型; llama 3 meta 开源的最新llama大模型; 下载运行 1 ollama ollama run llama3 2 github 下载仓库,需要linux环境,windows可使用wsl; 接…...
苹果Mac用户下载VS Code(Universal、Intel Chip、Apple Silicon)哪个版本?
苹果macOS用户既可以下载通用版(Universal),软件将自动检测用户的处理器并进行适配。 也可以根据型号下载对应CPU的版本: 使用Intel CPU的Mac电脑可下载Intel Chip版本; 使用苹果自研M系列CPU的Mac电脑下载Apple Si…...
Linux(Ubuntu)安装CGAL(非root)
一、安装boost 下载地址:Boost C Libraries - Browse /boost at SourceForge.net 我安装的是1.77.0的版本 ./bootstrap.sh --prefix/usr/local/boost ./b2 ./b2 install 配置环境变量 vim ~/.bashrcexport BOOST_INCLUDE/usr/local/boost/include export BO…...
hadoop学习---基于Hive的教育平台数据仓库分析案例(三)
衔接第一部分,第一部分请点击:基于Hive的教育平台数据仓库分析案例(一) 衔接第二部分,第二部分请点击:基于Hive的教育平台数据仓库分析案例(二) 学生出勤模块(全量分析):…...
RAFT:引领 Llama 在 RAG 中发展
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...
上海亚商投顾:沪指缩量调整 合成生物概念股持续爆发
上海亚商投顾前言:无惧大盘涨跌,解密龙虎榜资金,跟踪一线游资和机构资金动向,识别短期热点和强势个股。 一.市场情绪 沪指昨日缩量震荡调整,深成指、创业板指均跌超1%。细胞免疫治疗概念股大涨,冠昊生物、…...
Maven+Junit5 + Allure +Jenkins 搭建 UI 自动化测试实战
文章目录 效果展示Junit 5Junit 5 介绍Junit 5 与 Junit 4 对比PageFactory 模式编写自动化代码公共方法提取测试用例参数化Jenkins 搭建及配置参数化执行生成 Allure 报告Maven 常用命令介绍POM 文件效果展示 本 chat 介绍 UI 自动化测试框架的搭建: 运用 page factory 模式…...
docker学习笔记(三)搭建NFS服务实验
目录 什么是NFS 简单架构编辑 一.搭建nfs服务器 二.新建共享目录和网页文件 三.设置共享目录 四:创建使用nfs共享目录的卷 五:创建容器使用nfs-web-1卷 六:测试访问 七:是否同步测试 什么是NFS NFS 服务器:ne…...
super关键字
super关键字 在Java中,super是一个关键字,它用于引用当前对象的父类。在继承的关系中,子类可以通过super关键字来调用父类的构造方法、成员方法和成员变量。 super关键字的主要用途 调用父类的构造方法: 在子类的构造方法中&…...
【经典算法】LeetCode 200. 岛屿数量(Java/C/Python3/Go实现含注释说明,中等)
目录 题目描述思路及实现方式一:深度优先搜索(DFS)思路代码实现Java版本C语言版本Python3版本Golang版本 复杂度分析 方式二: 使用广度优先搜索(BFS)思路代码实现Java实现C实现Python3实现Go实现 总结相似题…...
Hive SQL-DQL-Select查询语句用法详解
HQL Select用法详解 1.基础语法 (1)select_exp (2)ALL、DISTINCT (3)WHERE (4)分区查询、分区裁剪 (5)GROUP BY (6)HAVING ࿰…...
沙盘Sandboxie v5.56.4
菜鸟高手裸奔工具沙盘Sandboxie是一款国外著名的系统安全工具,它可以让选定程序在安全的隔离环境下运行, 只要在此环境中运行的软件,浏览器或注册表信息等都可以完整的进行清空,不留一点痕迹。同时可以防御些 带有木马或者病毒的…...
Arcpy开发记录
一.GDB数据库相关 1.单独的shape更新时,不会有限制,数据会自动截取 2.在GDB下,使用UpdateCursor更新字段时,填入的数据长度必须与字段长度要求一致,否则报错: 二.Cursor相关 嵌套使用cursor时,…...
Android使用itextpdf操作PDF文档
1、导入jar包: itext-asian.jaritextpdf-5.5.8.jar Paragraph 和 Phrase 的区别: 在 iTextPDF 库中,Paragraph 和 Phrase 是用于创建和组织文本内容的两个不同的类。 Paragraph(段落): Paragraph 是一个…...
llama_index微调BGE模型
微调模型是为了让模型在特殊领域表现良好,帮助其学习到专业术语等。 本文采用llama_index框架微调BGE模型,跑通整个流程,并学习模型微调的方法。 已开源:https://github.com/stay-leave/enhance_llm 一、环境准备 Linux环境,GPU L20 48G,Python3.8.10。 pip该库即可。…...
什么是限流?常见的限流算法
目录 1. 什么是限流 2. 常见限流算法 3. 固定窗口算法 4. 滑动窗口算法 5. 漏桶算法 6. 令牌桶算法 7. 限流算法选择 1. 什么是限流 限流(Rate Limiting)是一种应用程序或系统资源管理的策略,用于控制对某个服务、接口或功能的访问速…...
ZL-0895小动物活动记录仪可同时检测8只动物的活动量
简单介绍: 小动物活动记录仪是一种多用途、宽范围的小动物活动记录仪器,可用于小鼠、大鼠、豚鼠和兔的实验,小动物活动记录仪具有不需对动物使用特别盛具的特点,可在不改变动物原生活环境的情况下,进行实时监测&…...
服装网站的建设与管理/seo网络优化招聘
小编又来了!!今天给大家带来的是蘑菇街广告投放系统的建设概要。相信大部分需要做流量召回和广告投放的公司都会关注这部分系统的建设。这里面也是不断在效果和成本上进行平衡,这次邀请了蘑菇街广告投放技术负责人腾哲给大家分享他的一些经验…...
wordpress 标签数量/做个网站
最基础的收集算法 —— 标记/清除算法 之所以说标记/清除算法是几种GC算法中最基础的算法,是因为后续的收集算法都是基于这种思路并对其不足进行改进而得到的。标记/清除算法的基本思想就跟它的名字一样,分为“标记”和“清除”两个阶段:首先…...
wordpress添加icp/seo公司
简单HTTP数据请求 超文本传输协议 (HTTP) 用作客户端和服务器之间的请求-响应协议。本实例将演示如何通过ESP8266发起一个HTTP请求,向远程主机请求数据。 在开始本实例之前,首先准备一个可用的HTTP服务器,或一个可用的HTTP URL。在这里,通过Node-Red物联网编程环境创建一…...
wordpress多用户模版/市场营销案例100例
marker on google Maps Page 186 在谷歌地图上增加你的地理坐标。 更多有关Google Maps JavaScript API http://code.google.com/apis/maps/documentation/javascript/ 使用方法如下。 需要在原来的基础上增加一个方法在上一篇博客的showMap()函数中。是加入 function addMarke…...
要建设一个网站需要什么手续/2022社会热点事件及看法
注:本篇文章很多并没有给出具体答案,因为每一个问题点都可以摊开讲许多相关联内容,其实最终还是需要我们自已去理解和实践,只有理解了其中本质才不会去做一个重复工作的程序员。写代码的时候时候都需要多问自已为什么要这种方式&a…...
织梦网站栏目不显示/苏州关键词优化排名推广
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼/*将移位寄存器内的数据锁存到输出寄存器并显示 *//* *//*******…...