现有一个新需求,用户可选择多个文件,多文件批量压缩下载,由于传统的代码效率不高,网上查询资料,对部分内容进行了修改与整合,特此留档
目录
一、导入依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.19</version>
</dependency>
二、创建HighEffiCompressZip工具类
将下面工具类中的内容直接复制即可
public class HighEffiCompressZip {
private String rootPaths;
ParallelScatterZipCreator scatterZipCreator = new ParallelScatterZipCreator();
// ParallelScatterZipCreator api says:
// 注意这个类不保证写入到输出文件的顺序。需要保持特定顺序的(manifests,文件夹)必须使用这个类的客户类进行处理
// 通常的做法是 在调用这个类的writeTo方法前把这些东西写入到ZipArchiveOutputStream
ScatterZipOutputStream dirs = ScatterZipOutputStream
.fileBased(File.createTempFile("whatever-preffix", ".whatever"));
public HighEffiCompressZip(String rootPaths) throws IOException {
this.rootPaths = rootPaths;
}
public HighEffiCompressZip() throws IOException {
}
public void addEntry(final ZipArchiveEntry zipArchiveEntry, final InputStreamSupplier streamSupplier)
throws IOException {
if (zipArchiveEntry.isDirectory() && !zipArchiveEntry.isUnixSymlink()) {
dirs.addArchiveEntry(ZipArchiveEntryRequest.createZipArchiveEntryRequest(zipArchiveEntry, streamSupplier));
} else {
scatterZipCreator.addArchiveEntry(zipArchiveEntry, streamSupplier);
}
}
public void writeTo(final ZipArchiveOutputStream zipArchiveOutputStream)
throws IOException, ExecutionException, InterruptedException {
dirs.writeTo(zipArchiveOutputStream);
dirs.close();
scatterZipCreator.writeTo(zipArchiveOutputStream);
}
public String getRootPaths() {
return rootPaths;
}
public void setRootPaths(String rootPath) {
this.rootPaths = rootPaths;
}
}
三、创建HighEffiCompressZipTest类内容
1、公共方法
@RestController
public class HighEffiCompressZipTest {
class CustomInputStreamSupplier implements InputStreamSupplier {
private File currentFile;
public CustomInputStreamSupplier(File currentFile) {
this.currentFile = currentFile;
}
@Override
public InputStream get() {
try {
// InputStreamSupplier api says:
// 返回值:输入流。永远不能为Null,但可以是一个空的流
return new FileInputStream(currentFile);
// return currentFile.isDirectory() ? new NullInputStream(0) : new FileInputStream(currentFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
private void addEntry(String entryName, File currentFile, HighEffiCompressZip scatterSample) throws IOException {
ZipArchiveEntry archiveEntry = new ZipArchiveEntry(entryName);
archiveEntry.setMethod(ZipEntry.DEFLATED);
final InputStreamSupplier supp = new CustomInputStreamSupplier(currentFile);
scatterSample.addEntry(archiveEntry, supp);
}
private void addEntryOneDir(String entryName, File currentFile, HighEffiCompressZip scatterSample) throws IOException {
ZipArchiveEntry archiveEntry = new ZipArchiveEntry(entryName);
archiveEntry.setMethod(ZipEntry.DEFLATED);
final InputStreamSupplier supp = new CustomInputStreamSupplier(currentFile);
scatterSample.addEntry(archiveEntry, supp);
}
private void compressCurrentDirectory(List<String> dir, HighEffiCompressZip scatterSample) throws IOException {
if (dir == null) {
throw new IOException("源路径不能为空!");
}
String relativePath = "";
// // if (dir.isFile()) {
// // relativePath = dir.getName();
// addEntry("download", null, scatterSample);
// return;
// }
// // 空文件夹
// if (dir.listFiles().length == 0) {
// relativePath = dir.getAbsolutePath().replace(scatterSample.getRootPath(), "");
// addEntry(relativePath + File.separator, dir, scatterSample);
// return;
// }
for (String file : dir) {
File f = new File(file);
if (!f.isDirectory()){
addEntry(f.getName(), f, scatterSample);//此种写法是多种文件压缩到一个文件夹中
// relativePath = f.getParent().replace(scatterSample.getRootPaths(), "");
// addEntry(relativePath + File.separator + f.getName(), f, scatterSample);//此种写法是压缩包中包括文件夹路径
}
}
}
private void compressCurrentDirectoryOneDir(File dir, HighEffiCompressZip scatterSample) throws IOException {
if (dir == null) {
throw new IOException("源路径不能为空!");
}
String relativePath = "";
if (dir.isFile()) {
relativePath = dir.getName();
addEntryOneDir(relativePath, dir, scatterSample);
return;
}
// 空文件夹
if (dir.listFiles().length == 0) {
relativePath = dir.getAbsolutePath().replace(scatterSample.getRootPaths(), "");
addEntryOneDir(relativePath + File.separator, dir, scatterSample);
return;
}
for (File f : dir.listFiles()) {
if (f.isDirectory()) {
compressCurrentDirectoryOneDir(f, scatterSample);
} else {
relativePath = f.getParent().replace(scatterSample.getRootPaths(), "");
addEntryOneDir(relativePath + File.separator + f.getName(), f, scatterSample);
}
}
}
private void compressCurrentDirectoryTree(List<String> dir, HighEffiCompressZip scatterSample) throws IOException {
if (dir == null) {
throw new IOException("源路径不能为空!");
}
String relativePath = "";
// // if (dir.isFile()) {
// // relativePath = dir.getName();
// addEntry("download", null, scatterSample);
// return;
// }
// // 空文件夹
// if (dir.listFiles().length == 0) {
// relativePath = dir.getAbsolutePath().replace(scatterSample.getRootPath(), "");
// addEntry(relativePath + File.separator, dir, scatterSample);
// return;
// }
for (String file : dir) {
File f = new File(file);
if (!f.isDirectory()){
// addEntry(f.getName(), f, scatterSample);//此种写法是多种文件压缩到一个文件夹中
// relativePath = f.getParent().replace(scatterSample.getRootPaths(), "");
addEntry(relativePath + File.separator + f.getName(), f, scatterSample);//此种写法是压缩包中包括文件夹路径
}
}
}
}
2、将多个文件放在一个文件夹中压缩下载
//压缩多文件(文件全放入根文件夹)
public void createZipFile(final List<String> rootPaths, final BufferedOutputStream result) throws Exception {
// File dstFolder = new File(result.getParent());
// if (!dstFolder.isDirectory()) {
// dstFolder.mkdirs();
// }
final HighEffiCompressZip scatterSample = new HighEffiCompressZip("zip");
compressCurrentDirectory(rootPaths, scatterSample);
final ZipArchiveOutputStream zipArchiveOutputStream = new ZipArchiveOutputStream(result);
scatterSample.writeTo(zipArchiveOutputStream);
zipArchiveOutputStream.close();
}
3、保留多文件文件夹的树形关系,整体压缩下载
//压缩多文件,保留文件夹树形关系
public void createZipFileTree(final List<String> rootPaths, final BufferedOutputStream result) throws Exception {
final HighEffiCompressZip scatterSample = new HighEffiCompressZip("zip");
compressCurrentDirectoryTree(rootPaths, scatterSample);
final ZipArchiveOutputStream zipArchiveOutputStream = new ZipArchiveOutputStream(result);
scatterSample.writeTo(zipArchiveOutputStream);
zipArchiveOutputStream.close();
}
4、保留子文件夹树形关系,将单个文件夹所有内容压缩下载
//压缩单个文件夹
private void createZipFileOneDir(final String rootPath, final BufferedOutputStream result) throws Exception {
// File dstFolder = new File(result.getParent());
// if (!dstFolder.isDirectory()) {
// dstFolder.mkdirs();
// }
File rootDir = new File(rootPath);
final HighEffiCompressZip scatterSample = new HighEffiCompressZip(rootDir.getAbsolutePath());
compressCurrentDirectoryOneDir(rootDir, scatterSample);
final ZipArchiveOutputStream zipArchiveOutputStream = new ZipArchiveOutputStream(result);
scatterSample.writeTo(zipArchiveOutputStream);
zipArchiveOutputStream.close();
}
四、方法测试
1、测试将多个文件放入一个文件夹中压缩下载
@Test
public void testSample(HttpServletResponse response) throws Exception {
SimpleDateFormat f = new SimpleDateFormat("yyyyMMddHHmmss");
OutputStream os = response.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
response.setHeader("content-disposition", "attachment;fileName=" + URLEncoder.encode(f.format(new Date()) + ".zip", "UTF-8"));
//批量多文件
long begin = System.currentTimeMillis();
System.out.println(new Date());
List<String> urls = new ArrayList<String>();
urls.add("F:/usr/local/mediaData/data/P001.jpg");
urls.add("F:/usr/local/mediaData/data/P002.jpg");
urls.add("F:/usr/local/mediaData/data/11/1.txt");
createZipFile(urls, bos);
long end = System.currentTimeMillis();
System.out.println("用时:" + (end - begin) + " ms");
System.out.println(new Date());
}
2、测试保留多文件文件夹树形关系,整体压缩下载
@Test
public void testSampleTwo(HttpServletResponse response) throws Exception {
SimpleDateFormat f = new SimpleDateFormat("yyyyMMddHHmmss");
OutputStream os = response.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
response.setHeader("content-disposition", "attachment;fileName=" + URLEncoder.encode(f.format(new Date()) + ".zip", "UTF-8"));
//批量多文件
long begin = System.currentTimeMillis();
System.out.println(new Date());
List<String> urls = new ArrayList<String>();
urls.add("F:/usr/local/mediaData/data/P001.jpg");
urls.add("F:/usr/local/mediaData/data/P002.jpg");
urls.add("F:/usr/local/mediaData/data/11/1.txt");
createZipFileTree(urls, bos);
long end = System.currentTimeMillis();
System.out.println("用时:" + (end - begin) + " ms");
System.out.println(new Date());
}
3、测试保留子文件夹树形关系
@Test
public void testSampleThree(HttpServletResponse response) throws Exception {
SimpleDateFormat f = new SimpleDateFormat("yyyyMMddHHmmss");
OutputStream os = response.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
response.setHeader("content-disposition", "attachment;fileName=" + URLEncoder.encode(f.format(new Date()) + ".zip", "UTF-8"));
//批量整个文件夹
long begin = System.currentTimeMillis();
// final File result = new File("F:/text1.zip");
// OutputStream os = response.getOutputStream();
// BufferedOutputStream bos = new BufferedOutputStream(os);
createZipFileOneDir("F:/usr/local/mediaData/data", bos);
long end = System.currentTimeMillis();
System.out.println("用时:" + (end - begin) + " ms");
}