原博客:https://blog.csdn.net/ahau10/article/details/52550430/
压缩效率
win10 环境。linux 会更快
代码
- 引入 commons-compress 坐标
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.20</version>
</dependency>
- 创建 ScatterSample.java
public class ScatterSample {
private String rootPath;
ParallelScatterZipCreator scatterZipCreator = new ParallelScatterZipCreator();
/**
* ParallelScatterZipCreator api says:
* 注意这个类不保证写入到输出文件的顺序。需要保持特定顺序的(manifests,文件夹)必须使用这个类的客户类进行处理
* 通常的做法是 在调用这个类的writeTo方法前把这些东西写入到ZipArchiveOutputStream
*/
ScatterZipOutputStream dirs = ScatterZipOutputStream
.fileBased(File.createTempFile("whatever-preffix", ".whatever"));
public ScatterSample(String rootPath) throws IOException {
this.rootPath = rootPath;
}
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 getRootPath() {
return rootPath;
}
public void setRootPath(String rootPath) {
this.rootPath = rootPath;
}
}
- 创建压缩工具类
public class ZipUtilParallelScatter {
/**
* 压缩
*
* @param source 将要被压缩的文件
* @param zipFile 压缩后的文件
* @return 压缩后的文件路径
*/
public String doZipFile(File source, File zipFile) {
try {
File zipFileParent = new File(zipFile.getParent());
// 若 压缩文件的路径 不存在,则创建出来
if (!zipFileParent.exists()) {
zipFileParent.mkdirs();
}
ScatterSample scatterSample = new ScatterSample(source.getAbsolutePath());
compressCurrentDirectory(scatterSample, source);
ZipArchiveOutputStream zipArchiveOutputStream = new ZipArchiveOutputStream(zipFile);
scatterSample.writeTo(zipArchiveOutputStream);
zipArchiveOutputStream.close();
return zipFile.getAbsolutePath();
} catch (IOException | InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
private void compressCurrentDirectory(ScatterSample scatterSample, File source) throws IOException {
if (source == null) {
throw new IOException("源路径不能为空!");
}
String relativePath = "";
if (source.isFile()) {
relativePath = source.getName();
addEntry(relativePath, source, scatterSample);
return;
}
// 空文件夹
if (Objects.requireNonNull(source.listFiles()).length == 0) {
relativePath = source.getAbsolutePath().replace(scatterSample.getRootPath(), "");
addEntry(relativePath + File.separator, source, scatterSample);
return;
}
for (File f : Objects.requireNonNull(source.listFiles())) {
if (f.isDirectory()) {
compressCurrentDirectory(scatterSample, f);
} else {
relativePath = f.getParent().replace(scatterSample.getRootPath(), "");
addEntry(relativePath + File.separator + f.getName(), f, scatterSample);
}
}
}
private void addEntry(String entryName, File currentFile, ScatterSample scatterSample) throws IOException {
ZipArchiveEntry archiveEntry = new ZipArchiveEntry(entryName);
archiveEntry.setMethod(ZipEntry.DEFLATED);
final InputStreamSupplier supp = new CustomInputStreamSupplier(currentFile);
scatterSample.addEntry(archiveEntry, supp);
}
class CustomInputStreamSupplier implements InputStreamSupplier {
private File currentFile;
public CustomInputStreamSupplier(File currentFile) {
this.currentFile = currentFile;
}
@Override
public InputStream get() {
try {
// InputStreamSupplier api says:
// 返回值:输入流。永远不能为Null,但可以是一个空的流
return currentFile.isDirectory() ? new NullInputStream(0) : new FileInputStream(currentFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
}
- 测试
public class ZipUtilsTest {
private File source = new File("F:\\upload");
String targetPath = "F:/upload_" + System.currentTimeMillis() + ".zip";
private File target = new File(targetPath);
@Test
public void testZipUtilParallelScatter() {
long start = System.currentTimeMillis();
ZipUtilParallelScatter zipUtil = new ZipUtilParallelScatter();
final String zipPath = zipUtil.doZipFile(source, target);
System.out.println("耗时:" + (System.currentTimeMillis() - start) + ";压缩文件路径:" + zipPath);
}
}
- 扩展
可以将文件分批,改成多线程并发 执行 压缩方法
参考:
Java 高效压缩zip
使用Java ParallelScatterZipCreator快速压缩文件夹(Fast zipping folder using java ParallelScatterZipCreator)