文件夹的批量下载

1.业务背景

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

 文件夹的批量下载_第1张图片

2.遇到问题

        刚准备开始写,就头疼,文件只要获得数据输出流就行,但是这文件夹需要维护层级关系。文件夹的批量下载_第2张图片

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

文件夹的批量下载_第3张图片

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

3.解决思路

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

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

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

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

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

        1.下载

   /**
     * 批量下载文件或者文件夹
     *
     * @param host      服务器地址
     * @param port      端口号
     * @param username  用户名
     * @param password  密码
     * @param downPaths 远程路徑
     * @return void
     */

    public Map batchDownloadFilesOrFolder(String host, int port, String username, String password, List downPaths) throws IOException {
        FTPClient ftp = getFtpClient(host, port, username, password);
        Map 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 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 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 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) {
            // 处理异常
        }
    }

你可能感兴趣的:(java,笔记,java)