使用ZipOutputStream压缩文件、文件夹,最后输出
①使用Spring,文件在线URL输出到请求响应response,提供下载
ZipOutputStream实现了一个输出流过滤器,用于以ZIP文件格式写入文件。包括对压缩项和未压缩项的支持。
用到的方法:
putNextEntry(ZipEntry entry);
传ZipEntry类,相当于在压缩包中放了一个文件,文件内容为空
ZipEntry有一个构造器,可以实现以路径的形式生成文件夹,例如new ZipEntry("a/b/c.jpg")
,最终生成的压缩包中包含a文件夹,a文件夹内部包含b,b文件夹内部包含c.jpg,利用这个性质,就可以写一个递归,检索文件夹,如果检索过程中又发现文件夹,则继续递归。
假设一个实体CloudFile
public class CloudFile {
private String fileName;//文件名称
private String fileUrl;//文件的url,一个在线的路径
private String filePath;//路径
}
下面基于在线的URL文件实现,提供思路:
public void downloadDir(List<CloudFile> fileList, HttpServletResponse response) {
ZipOutputStream zos = null;//最终输出的一个zip
try {
zos = new ZipOutputStream(response.getOutputStream());
downloadDir(zos, fileList, "");//递归下载,初始父路径为空
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
if (zos != null) {
zos.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
private void downloadDir(ZipOutputStream zos, List<CloudFile> fileList, String parentPath) {
try {
for (CloudFile file : fileList) {
//当前文件的路径
String nextPath = parentPath + "/" + file.getFileName();
if (nextPath.charAt(0) == '/') {
//避免文件夹以/开头
nextPath = nextPath.substring(1);
}
if (file.getDirFlag().equals(DirEnum.DIR.getCode())) {
List<CloudFile> nextList = baseMapper.selectList(Wrappers.<CloudFile>lambdaQuery()
.likeRight(CloudFile::getFilePath, file.getFilePath() + "/" + file.getFileName()));//类似查这个文件夹下的所有数据
downloadDir(zos, nextList, nextPath);//继续下载文件夹
continue;
}
zos.putNextEntry(new ZipEntry(nextPath));//放入当前下载的文件名称
zos.write(IOUtils.toByteArray(new URI(file.getFileUrl()).toURL()));//从URL中写入流 commons-io
zos.flush();
zos.closeEntry();
}
} catch (IOException | URISyntaxException e) {
throw new RuntimeException(e);
}
}
第一次调用先查出要下载的目录fileList
调用downloadDir(fileList, response)即可(无论是文件还是文件夹,这个方法都通用)
List<CloudFile> list = cloudFileService.list(
Wrappers.<CloudFile>lambdaQuery().eq(CloudFile::getUserId, SecurityUtil.getUserId())
.likeRight(CloudFile::getFilePath, tmp)
);
downloadDir(list, response);
②使用本地文件夹,压缩成zip输出到相应目录
以上是从URL中提取并且下载,如果是本地File文件呢???
假设要下载这样路径的一个文件夹
—ovo-test
——aaa.txt 文件
——ovo-test2 文件夹
———bbb.txt 文件
类似上面说到的方式
public static void downloadDir(File file) {
File outFile = new File("test.zip");//输出的zip
ZipOutputStream zos = null;
try {
zos = new ZipOutputStream(new FileOutputStream(outFile));
downloadDir(zos, file, "");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} finally {
try {
zos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
private static void downloadDir(ZipOutputStream zos, File file, String parentPath) {
try {
for (File childrenFile : file.listFiles()) {
String nextPath = parentPath + "/" + childrenFile.getName();
if (nextPath.charAt(0) == '/') {
nextPath = nextPath.substring(1);
}
if (childrenFile.isDirectory()) {
downloadDir(zos, childrenFile, nextPath);
return;
}
zos.putNextEntry(new ZipEntry(nextPath));
zos.write(childrenFile.getAbsolutePath().getBytes(StandardCharsets.UTF_8));
// zos.write(IOUtils.toByteArray(new FileInputStream(childrenFile))) 或者这样,用commons-io
zos.flush();
zos.closeEntry();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
File file = new File("D:\\ovo-test");
downloadDir(file);
}
执行main函数即可看到对应文件下的输出结果