文件夹的批量下载

news2024/12/25 22:33:05

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.coloradmin.cn/o/918738.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Postman高级用法——newman安装运行

newman是为postman而生专门的执行软件&#xff0c;newman执行脚本即非GUI方式执行&#xff08;命令行方式&#xff09; 下面为newman安装运行的详细操作&#xff01;&#xff01;&#xff01;&#xff08;认真看噢&#xff09; &#xff08;1&#xff09;安装node.js&#xf…

多个promise并发执行,如果某个promise失败,则尝试重新执行该promise一次,如果还是失败则提示错误

思路 可以使用 Promise.all()和Promise.catch() 结合的方式来实现多个promise的并发执行&#xff0c;并在某个promise失败时尝试重新执行。 首先&#xff0c;将所有的promise放入数组中&#xff0c;并使用Promise.all()来同时执行这些promise&#xff0c;这样可以确保所有的p…

利用 XGBoost 进行时间序列预测

推荐&#xff1a;使用 NSDT场景编辑器 助你快速搭建3D应用场景 XGBoost 应用程序的常见情况是分类预测&#xff08;如欺诈检测&#xff09;或回归预测&#xff08;如房价预测&#xff09;。但是&#xff0c;也可以扩展 XGBoost 算法以预测时间序列数据。它是如何工作的&#xf…

【业务功能篇73】web系统架构演变-单体-集群-垂直化-服务化-微服务化

1.服务架构的演 1.1 单体架构 单体架构应该是我们最先接触到的架构实现了&#xff0c;在单体架构中使用经典的三层模型&#xff0c;即表现层&#xff0c;业务逻辑层和数据访问层。 单体架构只适合在应用初期&#xff0c;且访问量比较下的情况下使用&#xff0c;优点是性价比很…

Redis五种类型

Redis 基础类型 String 应用场景 缓存功能&#xff1a;string 最常用的就是缓存功能&#xff0c;会将一些更新不频繁但是查询频繁的数据缓存起来&#xff0c;以此来减轻 DB 的压力。 底层实现 如果字符串对象保存的是一个字符串值&#xff0c; 并且这个字符串值的长度大于…

【2023中国算力大会】高质量建设西部数谷,努力把宁夏打造成算力之都

2023年8月18日—19日&#xff0c;2023中国算力大会在宁夏银川举行&#xff0c;本届大会以“算领新产业潮流 力赋高质量发展”为主题&#xff0c;打造“主题论坛、成果展示、产业推介、先锋引领”四大核心内容&#xff0c;全面展示算力产业发展最新成果&#xff0c;为产业各方搭…

servlet介绍,tomcat容器下载启动

1.1servlet是什么&#xff1f; servlet是一种java程序类&#xff0c;这些类继承了httpservlet类。这些类没有main方法&#xff0c;有两大对象request请求&#xff0c; response响应对象。这些类需要servlet容器才可以运行。 servlet 2.5 servlet 3.0 WEB-INF/web.xml <…

Docker安装并配置Pushgateway

Linux下安装Docker请参考&#xff1a;Linux安装Docker 简介 Pushgateway是Prometheus的一个组件&#xff0c;prometheus server默认是通过Exporter主动获取数据&#xff08;默认采取pull拉取数据&#xff09;&#xff0c;Pushgateway则是通过exporter主动方式推送数据到Pushg…

BlazorServer中C#与JavaScript的相互调用

BlazorServer中C#与JavaScript的相互调用 前言&#xff1a; ​ 虽然BlazorServer中推荐使用C#在razor页面中的替代JavaScript来完成逻辑的编写&#xff0c;但当需要使用第三方的javascript文件/组件里的内容时&#xff0c;则难免要在C#中调用其方法或对象。反之当你的(用到第…

性能调优篇 二、Jvm监控及诊断工具-命令行篇

目录 一、概述1、简单命令行工具 二、jps&#xff1a;查看正在运行的Java程序&#xff08;掌握&#xff09;1、是什么&#xff1f;2、测试3、基本语法 三、jstat&#xff1a;查看jvm统计信息&#xff08;掌握&#xff09;1、是什么&#xff1f;2、基本语法3、补充 四、jinfo&am…

avue-ueditor中隐藏部分工具栏

项目中不需要那么多工具栏,只需要展示部分工具栏 <avue-ueditor v-model"content" v-bind"options" :customConfig"customConfig" :placeholder"placeholder"></avue-ueditor>//按需隐藏或者显示工具栏即可 props: {custo…

数据结构(6)

2-3查找树 2-结点&#xff1a;含有一个键(及其对应的值)和两条链&#xff0c;左链接指向2-3树中的键都小于该结点&#xff0c;右链接指向的2-3树中的键都大于该结点。 3-结点&#xff1a;含有两个键(及其对应的值)和三条链&#xff0c;左链接指向的2-3树中的键都小于该结点&a…

WPF中的数据转换-StringFormat

WPF中的数据转换-StringFormat 前言 字符串格式化。使用该功能可以通过设置Binding.StringFormat属性对文本形式的数据进行转换——例如包含日期和数字的字符串。对于至少一半的格式化任务&#xff0c;字符串格式化是一种便捷的技术。 使用 当设置Binding.StringFormat属性…

因为计算机丢失vcruntime140.dll如何修复,教你如何快速修复

前几天&#xff0c;我在使用电脑时遇到了一个棘手的问题——我的电脑上的一个程序(软件名称)突然无法运行&#xff0c;提示我缺少vcruntime140.dll文件。这让我感到非常烦恼&#xff0c;因为我并不清楚如何解决这个问题。在经过一番尝试和搜索后&#xff0c;我终于找到了解决方…

Java进阶(7)——手动实现LinkedList 内部node类的实现 增删改查的实现 toString方法 源码的初步理解

目录 引出从ArrayList到Linkedlist手动实现ArrayList从ArrayList到LinkedList 总体设计Node类Node的方法&#xff1a;根据index找node 增删改查的实现增加元素删除元素修改元素查询元素 toString方法完整代码List接口类LinkedList的实现测试类 总结 引出 1.linkedList的节点&am…

Unity之 Vector3 的详细介绍以及方法的介绍

文章目录 总的介绍小试牛刀相关的描述的参数看个小例子 总的介绍 当涉及到Unity中的Vector3类时&#xff0c;以下是一些常用的方法和操作&#xff1a; magnitude 方法&#xff1a;返回向量的长度。 float length vector.magnitude;sqrMagnitude 方法&#xff1a;返回向量的平…

Sakana AI致力于打造日本人工智能界的top公司

原创 | 文 BFT机器人 01 Sakana AI创始人 Sakana AI 是一家总部位于东京的突破性创业公司&#xff0c;由前谷歌Brain研究员David Ha和Llion Jones共同创立。David Ha拥有多年且丰富的经验&#xff0c;曾担任Stability AI Ltd的研究负责人&#xff0c;并在Google LLC的日本人工…

ClickHouse领域集大成之作:《ClickHouse入门、实战与进阶》(文末送书)

前言 ClickHouse是大数据实时分析领域的主流选择之一。ClickHouse的目标是向人们提供世界上最快的分析型数据库。在各种OLAP查询引擎评测中&#xff0c;ClickHouse的查询性能横扫各大OLAP数据库引擎&#xff0c;尤其是Ad Hoc即席查询性能&#xff0c;一直遥遥领先。因此&#…

jenkins运行pytest测试用例脚本报错:没有权限,无法写日志PermissionError:[Error 13]Permission denied

报错信息&#xff1a; PermissionError:[Error 13]Permission denied&#xff1a;‘/var/jenkins_home/workspace/deleverySystem/Delivery_System/out_files/logs/waimai_20230823.log’ 解决方法&#xff1a; 在jenkins容器内部输入 chmod -R 777 /var/jenkins_home/works…