文件夹、文件目录递归下载:打包成ZIP压缩包在Java中如果要实现文件夹、文件目录的递归下载并打包成ZIP压缩包,可以通
文件目录下载并打包成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());
}
}
}
转载自:https://juejin.cn/post/7423907877554257955