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) {
            // 处理异常
        }
    }


















![jenkins运行pytest测试用例脚本报错:没有权限,无法写日志PermissionError:[Error 13]Permission denied](https://img-blog.csdnimg.cn/93f2bf078f22492bacd4e3ad1356cfd3.png#pic_center)