Java 高效压缩zip

以前遇到文件压缩的功能是都直接从网上找一个,随便测试一下能用就行了。既不关心效率也没有好好的测一下是否支持内嵌文件夹的压缩。

现在仔细测试才发现网上好多都不支持内嵌文件夹的压缩。 支持的不是有问题就是速度比较慢。

框架里jar包里的类诸如IOUtils,FileUtils里没有提供压缩的方法。连commons-compress.jar里都没有现成的。

我决定自己写一个。真写的时候发现不是那么容易。目标是 给定一个文件夹路径和一个输出路径,将给定文件夹里的所有东西都压缩到zip里。

在commons-compress的文档里发现有一个支持多线程压缩的类 ParallelScatterZipCreator。我决定试一试。

在github里找到 ScatterSample.java  和  ScatterSampleTest.java 这两个类。这个demo不支持带文件夹的压缩。
文档里也没有给出带文件夹压缩的demo。没办法只能仔细阅

读这个demo从api里找线索了。

仔细摸索后,代码如下:

package test;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.ExecutionException;

import org.apache.commons.compress.archivers.zip.ParallelScatterZipCreator;
import org.apache.commons.compress.archivers.zip.ScatterZipOutputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntryRequest;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.compress.parallel.InputStreamSupplier;

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;
    }

}
package test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;

import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.compress.parallel.InputStreamSupplier;
import org.apache.commons.io.input.NullInputStream;
import org.junit.Test;

public class ScatterSampleTest {

    @Test
    public void testSample() throws Exception {
        long begin = System.currentTimeMillis();
        final File result = new File("d:/test2/eclipse2.zip");
        createZipFile("F:/Java/eclipseplusUIx64_best", result);
        long end = System.currentTimeMillis();
        System.out.println("用时:" + (end - begin) + " ms");
    }

    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;
        }
    }

    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);
    }

    private void compressCurrentDirectory(File dir, ScatterSample scatterSample) throws IOException {
        if (dir == null) {
            throw new IOException("源路径不能为空!");
        }
        String relativePath = "";
        if (dir.isFile()) {
            relativePath = dir.getName();
            addEntry(relativePath, dir, scatterSample);
            return;
        }

        // 空文件夹
        if (dir.listFiles().length == 0) {
            relativePath = dir.getAbsolutePath().replace(scatterSample.getRootPath(), "");
            addEntry(relativePath + File.separator, dir, scatterSample);
            return;
        }
        for (File f : dir.listFiles()) {
            if (f.isDirectory()) {
                compressCurrentDirectory(f, scatterSample);
            } else {
                relativePath = f.getParent().replace(scatterSample.getRootPath(), "");
                addEntry(relativePath + File.separator + f.getName(), f, scatterSample);
            }
        }
    }

    private void createZipFile(final String rootPath, final File result) throws Exception {
        File dstFolder = new File(result.getParent());
        if (!dstFolder.isDirectory()) {
            dstFolder.mkdirs();
        }
        File rootDir = new File(rootPath);
        final ScatterSample scatterSample = new ScatterSample(rootDir.getAbsolutePath());
        compressCurrentDirectory(rootDir, scatterSample);
        final ZipArchiveOutputStream zipArchiveOutputStream = new ZipArchiveOutputStream(result);
        scatterSample.writeTo(zipArchiveOutputStream);
        zipArchiveOutputStream.close();
    }
}

以解压后的eclipse文件为例,用时:4624 ms。比较了一下网上其他的方法,快了2倍多。这结果还算满意。 代码水平有限,只能到这儿了。如果有更精简的代码,欢迎指教。

时间: 2024-09-01 11:51:49

Java 高效压缩zip的相关文章

在Java中操作Zip文件,压缩/解压

压缩 可随意转载,但请注明出处及作者SonyMusic2003.05.28==========================================================================在Java中操作Zip文件,压缩/解压 package test.nothing; import java.io.*;import java.util.*;import java.util.zip.*; import com.beaconsystem.util.*; impor

java压缩zip文件中文乱码问题解决方法_java

通常用java来打包文件生成压缩文件后,有如下两个地方会出现乱码 : 1.内容的中文乱码问题,这个问题网上很多人给出了解决方法,主要有两种方法:一是修改sun的源码:另一个是使用开源的类库org.apache.tools.zip.ZipOutputStream和org.apache.tools.zip.ZipEntry,这两个类ant.jar中有,可以直接下载使用即可,毫无疑问,选择后者更方便 2.压缩文件注释的中文乱码问题:zos.setComment("中文测试");这个问题网上对

递归-java 打包压缩下载出错,求大神帮忙

问题描述 java 打包压缩下载出错,求大神帮忙 代码在这里 package cn.mobilizer.channel.image.vo; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.ut

java 压缩-Java代码压缩带有空文件夹带来的问题

问题描述 Java代码压缩带有空文件夹带来的问题 Java代码压缩带来空文件夹的目录,执行完成之后,双击zip文件,发现空文件夹的文件类型变成了文件类型,本来期望的是文件夹就是文件交类型,求解释,以及如何将文件类型改为文件夹类型.

Java文件压缩与解压缩(一)

package com.cn; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutpu

Java 图片压缩实现思路及代码

本文为大家详细介绍下图片压缩的具体实现思路及java代码,想学习的各位可以参考下哈,希望对大家有所帮助   Java图片压缩代码 复制代码 代码如下: package com.img; import java.awt.Image; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import javax.im

使用Python压缩和解压缩zip文件的教程

  这篇文章主要介绍了使用Python压缩和解压缩zip文件的教程,主要用到了zipfile包,需要的朋友可以参考下 python 的 zipfile 提供了非常便捷的方法来压缩和解压 zip 文件. 例如,在py脚本所在目录中,有如下文件: 代码如下: readability/readability.js readability/readability.txt readability/readability-print.css readability/sprite-readability.pn

安卓后端-求Java高效合理排序算法

问题描述 求Java高效合理排序算法 安卓界面列表可任意拖拽变换列表数据顺序,保存数据在后端服务,怎样在后端实现排序,求各路高手指点,确切的方案也可以,大概思路方向也可以,希望大家不吝赐教,先谢过 解决方案 这个在排序的时候加上一个orderid,当你页面上改变位置的时候,就更新orderid发回去. 这个链接的前端可以借鉴http://www.cnblogs.com/breakdown/archive/2012/03/29/2423091.html

Java 图片压缩实现思路及代码_java

Java图片压缩代码 复制代码 代码如下: package com.img; import java.awt.Image; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import javax.imageio.ImageIO; import com.sun.image.codec.jpeg.JPEGCod