java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java文件目录下载

Java文件目录下载并打包成ZIP压缩包

作者:CodeDevMaster

这篇文章主要介绍了在Java中如何实现文件夹、文件目录的递归下载并打包成ZIP压缩包,文中的示例代码讲解详细,有需要的可以参考下

在Java中如果要实现文件夹、文件目录的递归下载并打包成ZIP压缩包,可以通过以下步骤进行:

遍历文件夹:使用递归方法遍历指定目录下的所有文件和文件夹

创建ZIP输出流:使用java.util.zip包中的ZipOutputStream类创建ZIP文件

将文件添加到ZIP:将遍历到的文件逐个添加到ZIP压缩包中

单个文件目录打包ZIP下载

单个文件目录打包ZIP下载与文件目录递归打包ZIP下载类似,首先来看看单个文件目录中的文件是如何打包ZIP下载的。

/**
 * 下载指定文件夹及其所有文件的内容,并将其打包为 ZIP 文件。
 *
 * @param folderId 需要下载的文件夹 ID
 * @param response HTTP 响应对象,用于发送 ZIP 文件
 * @throws IOException 在处理输入输出时可能抛出异常
 */
public void downloadFolder(Integer folderId, HttpServletResponse response) throws IOException {
    // 校验权限,检查用户是否有权限下载该文件夹
    Boolean isAuth = checkAuthService.checkAuthDownload(folderId);
    if (!isAuth) {
        // 如果没有权限,则抛出业务异常
        throw new BusinessException(TipsConstant.Tips_6002);
    }

    // 查询指定文件夹下的所有文件列表
    List<FileOrg> fileOrgList = getFileBeansByFolderId(folderId);
    // 获取文件夹信息,用于设置 ZIP 文件的名称
    FolderOrg folderOrg = folderOrgMappr.selectById(folderId);

    // 准备压缩文件的数据
    try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())) {
        // 设置响应头,准备发送 ZIP 文件
        prepareResponse(response, folderOrg.getName());
        // 将文件添加到 ZIP 压缩包中
        addFilesToZip(zipOutputStream, fileOrgList, folderOrg.getName());
    } catch (IOException e) {
        // 如果发生错误,返回 500 错误和错误信息
        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to download folder: " + e.getMessage());
    }
}

这里首先假设有一个目录:测试目录,里面有文件与文件目录。以下是针对单个文件目录打包ZIP下载实现的一个效果截图。

递归文件目录打包ZIP下载

递归文件目录打包ZIP下载相比单个文件目录打包ZIP下载,无非是多了个递归文件目录的操作。

    @Override
    public void recursiveDownload(Integer folderId, HttpServletResponse response) throws IOException {
         // 校验权限,检查用户是否有权限下载该文件夹
    Boolean isAuth = checkAuthService.checkAuthDownload(folderId);
    if (!isAuth) {
        // 如果没有权限,则抛出业务异常
        throw new BusinessException(TipsConstant.Tips_6002);
    }

        // 获取文件夹信息,用于设置 ZIP 文件的名称
	    FolderOrg folderOrg = folderOrgMappr.selectById(folderId);

        // 准备压缩文件的数据
        try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())) {
	        // 设置响应头,准备发送 ZIP 文件
            prepareResponse(response, folderOrg.getName());
            // 递归调用将子文件夹及其文件添加到 ZIP
            addFolderToZip(zipOutputStream, folderId, folderOrg.getName());
        } catch (IOException e) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to download folder: " + e.getMessage());
        }
    }

 这里首先假设有一个目录:测试目录,里面有文件与嵌套文件目录。以下是针对递归文件目录打包ZIP下载实现的一个效果截图。

设置响应头

基于上述代码,实现响应头的设置方法。在准备将文件打包成 ZIP 文件之前,需要设置 HTTP 响应的相关信息,包括字符编码、内容类型和文件名称。这将确保用户在下载时能够正确识别文件类型。

/**
 * 准备 HTTP 响应,设置响应头以便下载 ZIP 文件。
 *
 * @param response  HTTP 响应对象
 * @param folderName 文件夹名称,用于生成 ZIP 文件的名称
 * @throws IOException 在设置响应头时可能抛出异常
 */
private void prepareResponse(HttpServletResponse response, String folderName) throws IOException {
    // 设置字符编码
    response.setCharacterEncoding("UTF-8");
    // 设置下载文件的名称,使用 URL 编码以兼容特殊字符
    response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(folderName + ".zip", "UTF-8"));
    // 设置内容类型为 ZIP 文件
    response.setContentType("application/zip");
}

递归添加文件夹及文件

基于上述代码,实现addFolderToZip方法是实现递归的关键。它首先获取当前文件夹中的文件列表,然后将这些文件添加到ZIP中。接着,它会获取当前文件夹的所有子文件夹,并对每个子文件夹递归调用自身。

    /**
     * 递归处理文件夹及其子文件夹
     * 1.首先获取当前文件夹的文件列表,并调用 addFilesToZip 方法将文件添加到 ZIP 中。
     * 2.然后获取当前文件夹的子文件夹,并递归调用 addFolderToZip 方法处理每个子文件夹
     * @param zipOutputStream ZipOutputStream
     * @param folderId 文件夹ID
     * @throws IOException IO异常
     */
    private void addFolderToZip(ZipOutputStream zipOutputStream, Integer folderId, String parentFolderName) throws IOException {
        // 获取当前文件夹的文件列表
        List<FileOrg> fileOrgList = getFileBeansByFolderId(folderId);

        // 将当前文件夹的文件添加到 ZIP
        addFilesToZip(zipOutputStream, fileOrgList,parentFolderName);

        // 获取当前文件夹的子文件夹
        List<FolderOrg> subFolders = getSubFoldersByFolderId(folderId);
        for (FolderOrg subFolder : subFolders) {
            // 递归调用将子文件夹及其文件列表添加到 ZIP
            addFolderToZip(zipOutputStream, subFolder.getId(),parentFolderName + "/" + subFolder.getName());
        }
    }

获取子文件目录与文件列表

获取子文件夹与文件列表需根据自身业务实现,这里基于数据库查询子文件目录,查询文件目录下的文件,同时又涉及了一些处理业务逻辑。

1.获取当前文件夹的所有子文件夹

    /**
     * 获取指定文件夹下的所有子文件夹。
     * @param folderId 文件夹ID
     * @return List<FolderOrg>
     */
    private List<FolderOrg> getSubFoldersByFolderId(Integer folderId) {
        QueryWrapper<FolderOrg> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("deleted",0).eq("parent_id", folderId);
        List<FolderOrg> folderOrgs = folderOrgMappr.selectList(queryWrapper);
        return folderOrgs;
    }

2.获取文件夹下的文件列表

/**
 * 根据文件夹 ID 获取该文件夹下的所有文件信息。
 *
 * @param folderId 文件夹 ID
 * @return 文件组织列表,包含该文件夹下的所有文件信息
 */
private List<FileOrg> getFileBeansByFolderId(Integer folderId) {
    // 创建查询条件,查找该文件夹下的所有文件链接
    QueryWrapper<FileLinkOrg> queryWrapper1 = new QueryWrapper<>();
    queryWrapper1.eq("folder_id", folderId);
    List<FileLinkOrg> fileLinkOrgList = fileLinkOrgMapper.selectList(queryWrapper1);
    
    // 如果没有文件,返回空列表
    if (fileLinkOrgList.isEmpty()) {
        return new ArrayList<FileOrg>(0);
    }

    // 创建文件 ID 和名称的映射关系
    HashMap<String, String> fileNameMap = new HashMap<>();
    fileLinkOrgList.forEach(item -> fileNameMap.put(item.getFileId(), item.getFileName()));

    // 获取文件夹下所有文件的 ID
    ArrayList<String> fileIdList = new ArrayList<>(fileLinkOrgList.size());
    fileLinkOrgList.forEach(item -> fileIdList.add(item.getFileId()));

    // 根据文件 ID 查询文件存储信息
    QueryWrapper<FileOrg> queryWrapper2 = new QueryWrapper<>();
    queryWrapper2.in("id", fileIdList);
    List<FileOrg> fileOrgList = fileOrgMapper.selectList(queryWrapper2);

    // 更新文件组织列表中的文件名称
    fileOrgList.forEach(item -> item.setFileName(fileNameMap.get(item.getId())));

    return fileOrgList;
}

将文件添加到ZIP中

基于上述代码,实现addFilesToZip方法。需要将查询到的文件添加到 ZIP 输出流中。使用 ZipOutputStream 类来处理 ZIP 文件的创建和写入。在写入每个文件时,需要确保使用正确的路径和名称。

/**
 * 将指定文件列表中的文件添加到 ZIP 输出流中。
 *
 * @param zipOutputStream ZIP 输出流
 * @param fileOrgList 文件组织列表,包含待添加的文件信息
 * @throws IOException 在处理输入输出时可能抛出异常
 */
private void addFilesToZip(ZipOutputStream zipOutputStream, List<FileOrg> fileOrgList,String parentFolderName) throws IOException {
    // 遍历文件列表,将每个文件添加到 ZIP
    for (FileOrg fileOrg : fileOrgList) {
        try (InputStream inputStream = minioUtils.getObject(fileOrg.getBucketName(), fileOrg.getFilePath())) {
         	// 设置 ZIP 条目的路径,包括文件夹名称
            String zipEntryName = parentFolderName + "/" + fileOrg.getFileName();
            // 创建 ZIP 条目,使用文件名称
            zipOutputStream.putNextEntry(new ZipEntry(zipEntryName));
            byte[] buffer = new byte[2048];
            int length;
            // 读取文件内容并写入 ZIP 输出流
            while ((length = inputStream.read(buffer)) > 0) {
                zipOutputStream.write(buffer, 0, length);
            }
            // 关闭当前 ZIP 条目
            zipOutputStream.closeEntry();
        } catch (Exception e) {
            // 记录异常信息,继续处理其他文件
            log.info("-------------------- 打包ZIP下载异常: {}--------------------", e.getMessage());
        }
    }
}

到此这篇关于Java文件目录下载并打包成ZIP压缩包的文章就介绍到这了,更多相关Java文件目录下载内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文