文件夹的批量下载

news/2024/5/19 17:04:49/文章来源:https://blog.csdn.net/2201_75630288/article/details/132453684

1.业务背景

        公司想实现文件系统下载,上次图简单就草率的写了文件下载,这不趁着同事请假赶集吧这坑给填上。        

 

2.遇到问题

        刚准备开始写,就头疼,文件只要获得数据输出流就行,但是这文件夹需要维护层级关系。

        前端给的是服务器的绝对地址,还得服务器的文件名对的上,不然的下载个1.doc 2.txt 3.image,另外得考虑到如果文件夹下面的文件路径不存在会不会报错 

         因为每个文件夹的目录的和流关联起来 ,而且我们只知道下载的文件地址。所以在打成zip包的时候得考虑地址替换以及子文件夹创建的问题。

3.解决思路

        解决方法很简单,但可能一时半会给绕进去了,都想半天了。

        关于层级的问题:先去校验是否是文件进行递归操作 没啥难度

        关于路径的问题:使用下载路径作为根目录,是文件的时候将目录进行传递,也无需在打成zip包在做解析

        关于目录的问题:需要做标识,文件放的是字节数组,文件夹放的是null,在对应层级创建目录即可。

4.代码实现(展现ftp的实现方式)

        1.下载

   /*** 批量下载文件或者文件夹** @param host      服务器地址* @param port      端口号* @param username  用户名* @param password  密码* @param downPaths 远程路徑* @return void*/public Map<String, byte[]> batchDownloadFilesOrFolder(String host, int port, String username, String password, List<String> downPaths) throws IOException {FTPClient ftp = getFtpClient(host, port, username, password);Map<String, byte[]> fileBytesMap = new HashMap<>();for (String downPath : downPaths) {// 检查下载路径是否为文件夹String rootPath = StringUtils.getFileName(downPath);FTPFile ftpFile = ftp.mlistFile(downPath);if (ftpFile != null && ftpFile.isDirectory()) {fileBytesMap.put(rootPath , null);// 如果是文件夹,则递归调用下载文件夹的方法downloadDirectory(ftp, downPath, rootPath, fileBytesMap);} else {ByteArrayOutputStream outputStream = new ByteArrayOutputStream();if (!ftp.retrieveFile(downPath, outputStream)) {// 文件下载失败的处理逻辑,比如抛出异常或记录日志} else {fileBytesMap.put(rootPath, outputStream.toByteArray());}}}return fileBytesMap;}/*** 下载文件夹的方法** @param ftp* @param directoryPath* @param rootPath              根目录* @param fileBytesMap* @throws IOException*/private void downloadDirectory(FTPClient ftp, String directoryPath, String rootPath, Map<String, byte[]> fileBytesMap) throws IOException {FTPFile[] files = ftp.listFiles(directoryPath);for (FTPFile file : files) {String filePath = directoryPath + "/" + file.getName();String relativePath = rootPath + "/" + file.getName();if (file.isFile()) {ByteArrayOutputStream outputStream = new ByteArrayOutputStream();if (!ftp.retrieveFile(filePath, outputStream)) {// 文件下载失败的处理逻辑,比如抛出异常或记录日志} else {fileBytesMap.put(relativePath, outputStream.toByteArray());}} else if (file.isDirectory()) {// 递归调用下载文件夹的方法fileBytesMap.put(relativePath, null);downloadDirectory(ftp, filePath, relativePath, fileBytesMap);}}}

        2.打成zip包

    /*** 将下载的流写入zip** @param bytesMap* @param response*/private void downStreamWriteZip(Map<String, byte[]> bytesMap, HttpServletResponse response){try {// 设置响应头response.setHeader("Content-Disposition", "attachment; filename=files.zip");response.setContentType("application/zip");// 创建输出流ServletOutputStream outputStream = response.getOutputStream();ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);for (Map.Entry<String, byte[]> entry : bytesMap.entrySet()) {String fileName = entry.getKey();byte[] data = entry.getValue();if (data == null) {// 文件夹,需要创建目录结构ZipEntry zipEntry = new ZipEntry(fileName + "/");zipOutputStream.putNextEntry(zipEntry);zipOutputStream.closeEntry();} else {// 文件,写入文件数据ZipEntry zipEntry = new ZipEntry(fileName);zipOutputStream.putNextEntry(zipEntry);zipOutputStream.write(data);zipOutputStream.closeEntry();}}// 关闭流zipOutputStream.close();outputStream.close();} catch (IOException e) {// 处理异常}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_160560.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

(2023)Linux安装pytorch并使用pycharm远程编译运行

&#xff08;2023&#xff09;Linux安装pytorch并使用pycharm远程编译运行 安装miniconda 这部分参考我这篇博客的前半部分Linux服务器上通过miniconda安装R&#xff08;2022&#xff09;_miniconda 安装r_Dream of Grass的博客-CSDN博客 创建环境 创建一个叫pytorch的环境…

带你走进 字节跳动 消息队列

区别于#创作活动那一篇文章&#xff0c;这篇文章有我自己的重点内容颜色标记等注释&#xff0c;有注释的参加不了那个活动&#xff0c;所以发了两篇&#xff0c;不久之后那篇文章将会删除 消息队列前世今生 1.1 案例一&#xff1a; 系统崩溃 首先大家跟着我想象一下下面的这个的…

【解决问题】Transaction was marked for rollback only; cannot commit

问题现象&#xff1a; 导入文件的时候直接报错&#xff1a; Transaction was marked for rollback only; cannot commit; nested exception is org.hibernate.TransactionException: Transaction was marked for rollback only; cannot commit 中文意思大概是&#xff1a;事…

Cyanine5-alkyne在无机纳米领域的应用-星戈瑞

​欢迎来到星戈瑞荧光stargraydye&#xff01;小编带您盘点&#xff1a; Cyanine5-alkyne在无机纳米领域也有着诸多的应用&#xff0c;主要体现在以下几个方面&#xff1a; **1. 纳米颗粒表面功能化&#xff1a;**Cyanine5-alkyne作为反应性的炔基官能团&#xff0c;可以与含有…

uniapp 回退到指定页面 保存页面状态

uniapp 历史页面回退到指定页面。 getCurrentPages() 内容如下 let delta getCurrentPages().reverse().findIndex(item > item.route "pages/popularScience/daodi") if(delta-1){uni.navigateTo({url: /pages/popularScience/daodi,success: res > {},fa…

Linux后门大全-xinetd后门(二)

环境 靶机&#xff1a;centos7.6 攻击机&#xff1a;Linux 使用docker搭建靶机环境&#xff0c;当然也可以不使用docker&#xff0c;直接跳过创建容器的步骤即可 创建容器 #创建名为backdoorT4的特权容器&#xff0c;并使用/usr/sbin/init&#xff0c;因为容器默认不开启sy…

java电子病历源码 电子病历编辑器源码 病历在线制作、管理和使用

电子病历在线制作、管理和使用的一体化电子病历解决方案&#xff0c;通过一体化的设计&#xff0c;提供对住院病人的电子病历书写、保存、修改、打印等功能。电子病历系统将临床医护需要的诊疗资料以符合临床思维的方法展示。建立以病人为中心&#xff0c;以临床诊疗信息为主线…

Kubernetes(K8S)简介

Kubernetes (K8S) 是什么 它是一个为 容器化 应用提供集群部署和管理的开源工具&#xff0c;由 Google 开发。Kubernetes 这个名字源于希腊语&#xff0c;意为“舵手”或“飞行员”。k8s 这个缩写是因为 k 和 s 之间有八个字符的关系。 Google 在 2014 年开源了 Kubernetes 项…

C++模板与泛型编程:条款41~48

"绝境之中才窥见 winner winner 无限的精彩" 条款41: 了解隐式接口和编译器多态 我们给出一组类定义和函数实现(无意义): class Widget { public:Widget();virtual ~Widget();virtual size_t size() const;virtual void normalize();void swap(Widget&…

【核磁共振成像】傅里叶重建

目录 一、傅里叶重建二、填零三、移相四、数据窗函数五、矩形视野六、多线圈数据重建七、图像变形校正八、缩放比例九、基线校准 长TR&#xff0c;长TE&#xff0c;是T2加权像&#xff1b; 短TR&#xff0c;短TE&#xff0c;是T1加权像&#xff1b; 长TR&#xff0c;短TE&#…

Android BatteryManager的使用及BatteryService源码分析

当需要监控系统电量时&#xff0c;用 BatteryManager 来实现。 参考官网 监控电池电量和充电状态 获取电池信息 通过监听 Intent.ACTION_BATTERY_CHANGED 广播实现&#xff0c;在广播接收器中获取电池信息。 这是个粘性广播&#xff0c;即使过了广播发出的时间点后再注册广…

星戈瑞分析FITC-PEG-Alkyne的荧光特性和光谱特性

​欢迎来到星戈瑞荧光stargraydye&#xff01;小编带您盘点&#xff1a; FITC-PEG-Alkyne的荧光特性和光谱特性是对其荧光性能进行分析的方面。以下是FITC-PEG-Alkyne的一些常见荧光特性和光谱特性&#xff1a; **1. 荧光激发波长&#xff1a;**FITC-PEG-Alkyne的荧光激发波长通…

面试热题(不同的二分搜索树)

给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 经典的面试题&#xff0c;这部分涉及了组合数学中的卡特兰数&#xff0c;如果对其不清楚的同学可以去看我以前的博客卡特兰数 …

vue项目中使用ts的枚举类型

vue项目中要使用ts的枚举类型需要为script标签的lang属性添加ts属性值 <script lang"ts" setup> </script > 声明枚举类型&#xff1a; //语法 /* enum 枚举名称 {可能的值 }*/ enum scenic_status {"正常" 1,"审核中","暂停…

[CVPR 2023]PyramidFlow-训练并推理-附bug调试

CVPR2023-PyramidFlow-zero shot异常检测网络 代码调试记录 一.论文以及开源代码二.前期代码准备三.环境配置四.bug调试num_samples should be a positive integer value, but got num_samples0AttributeError: Cant pickle local object fix_randseed.<locals>.seed_wor…

恒运资本:抄底单是什么意思?

抄底单是指出资者在股票或其他金融产品跌幅较大时&#xff0c;以较低价格买入的清单。其目的是在商场低迷、经济不景气时通过较低买入价格获取更多的财物&#xff0c;等待商场反弹时出售&#xff0c;然后取得高额收益。一般来说&#xff0c;需求具有必定的专业常识和危险意识的…

vite创建项目命令

1.第一步运行创建命令&#xff08;npm&#xff09; npm create vitelatest也可以使用yarn yarn create vite还可以 pnpm create vite注意的地方&#xff1a;首次创建的时候会出现这个 Need to install the following packages:create-vitelatest Ok to proceed? (y) 直接y就…

C++入门:引用是什么

目录 1.引用的概念 2.引用的特征 3.常引用 4.引用使用场景 5.传值&#xff0c;传引用效率比较 6.引用与指针的区别 1.引用的概念 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空 间&#xff0c;它和它引用…

HDLBits-Verilog学习记录 | Verilog Language-Basics(2)

文章目录 9.Declaring wires | wire decl10. 7458 chip 9.Declaring wires | wire decl problem:Implement the following circuit. Create two intermediate wires (named anything you want) to connect the AND and OR gates together. Note that the wire that feeds the …

设计模式(11)观察者模式

一、概述&#xff1a; 1、定义&#xff1a;观察者模式定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象&#xff0c;使它们能够自动更新自己。 2、结构图&#xff1a; public interface S…