ZipCompressor.java是一个常见的压缩工具类,使用java的内置算法,可以用于压缩文件和文件夹。

这个工具类很简单,我们来看一下它的实现。

首先我们来看构造函数

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * zip压缩工具<br>
 * 含有中文请谨慎,zip文件在不同操作系统容易中文乱码.
 * 
 */
public class ZipCompressor {
    static final int BUFFER = 8192;

    private File zipFile;

    /**
     * 压缩器构造函数
     * 
     * @param pathName 压缩包路径<br>
     *            e.g /Users/Admin/Desktop/test.zip
     */
    public ZipCompressor(String pathName) {
        zipFile = new File(pathName);
        if (zipFile.exists()) {
            System.out.println("删除旧的压缩文件:" + pathName);
            zipFile.delete();
        }
    }
}



在构造函数中,我们获取pathName的文件对象,pathName就是压缩文件路径,如果这个文件存在,也就是有以前压缩的数据,我们先删除它

接下来是提供外部调用的压缩方法

/**
     * 压缩一个文件,或者一个文件夹
     * 
     * @param srcPathName 文件路径,或文件夹路径
     */
    public void compress(String srcPathName) {
        File file = new File(srcPathName);
        if (!file.exists())
            throw new RuntimeException(srcPathName + "不存在!");
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(zipFile);
            CheckedOutputStream cos = new CheckedOutputStream(fileOutputStream,
                    new CRC32());
            ZipOutputStream out = new ZipOutputStream(cos);
            String basedir = "";
            compress(file, out, basedir);
            out.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 压缩多个文件
     * 
     * @param filePaths 文件路径
     */
    public void compress(String[] filePaths) {
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(zipFile);
            CheckedOutputStream cos = new CheckedOutputStream(fileOutputStream,
                    new CRC32());
            ZipOutputStream out = new ZipOutputStream(cos);
            String basedir = "";
            for (int i = 0; i < filePaths.length; i++) {
                compress(new File(filePaths[i]), out, basedir);
            }
            out.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


上面有两个方法,分别用于压缩文件和文件夹,但是其实没有真正的压缩实现

首先是获得要压缩文件的输出流,将它封装成CheckedOutputStream,目的是为了指定文件校验算法。(通常使用CRC32算法)。

然后封装成ZipOutputStream流

调用compress()方法进行压缩

private void compress(File file, ZipOutputStream out, String basedir) {
        /* 判断是目录还是文件 */
        if (file.isDirectory()) {
            System.out.println("压缩:" + basedir + file.getName());
            this.compressDirectory(file, out, basedir);
        } else {
            System.out.println("压缩:" + basedir + file.getName());
            this.compressFile(file, out, basedir);
        }
    }

对于文件和文件夹,分别调用不同的方法

/** 压缩一个目录 */
    private void compressDirectory(File dir, ZipOutputStream out, String basedir) {
        if (!dir.exists())
            return;

        File[] files = dir.listFiles();
        for (int i = 0; i < files.length; i++) {
            /* 递归 */
            compress(files[i], out, basedir + dir.getName() + "/");
        }
    }

    /** 压缩一个文件 */
    private void compressFile(File file, ZipOutputStream out, String basedir) {
        if (!file.exists())
            return;
        try {
            BufferedInputStream bis = new BufferedInputStream(
                    new FileInputStream(file));
            ZipEntry entry = new ZipEntry(basedir + file.getName());
            out.putNextEntry(entry);
            int count;
            byte data[] = new byte[BUFFER];
            while ((count = bis.read(data, 0, BUFFER)) != -1) {
                out.write(data, 0, count);
            }
            bis.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

对于文件夹compressDirectory()方法中逐个去递归调用compress()方法,每次还要传入上级文件夹路径

只有是文件才进行真正的压缩


在compressFile()方法里面

获得要压缩文件的输入流

分装一个ZipEntry对象,ZipEntry就是压缩包中的每一个实体

这种设计条目对象的思想在文件处理中经常用到

然后提供一个缓冲池

使用ZipOutputStream的write()方法进行文件写入即可

完整代码:

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * zip压缩工具<br>
 * 含有中文请谨慎,zip文件在不同操作系统容易中文乱码.
 * 
 */
public class ZipCompressor {
    static final int BUFFER = 8192;

    private File zipFile;

    /**
     * 压缩器构造函数
     * 
     * @param pathName 压缩包路径<br>
     *            e.g /Users/Admin/Desktop/test.zip
     */
    public ZipCompressor(String pathName) {
        zipFile = new File(pathName);
        if (zipFile.exists()) {
            System.out.println("删除旧的压缩文件:" + pathName);
            zipFile.delete();
        }
    }

    /**
     * 压缩一个文件,或者一个文件夹
     * 
     * @param srcPathName 文件路径,或文件夹路径
     */
    public void compress(String srcPathName) {
        File file = new File(srcPathName);
        if (!file.exists())
            throw new RuntimeException(srcPathName + "不存在!");
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(zipFile);
            CheckedOutputStream cos = new CheckedOutputStream(fileOutputStream,
                    new CRC32());
            ZipOutputStream out = new ZipOutputStream(cos);
            String basedir = "";
            compress(file, out, basedir);
            out.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 压缩多个文件
     * 
     * @param filePaths 文件路径
     */
    public void compress(String[] filePaths) {
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(zipFile);
            CheckedOutputStream cos = new CheckedOutputStream(fileOutputStream,
                    new CRC32());
            ZipOutputStream out = new ZipOutputStream(cos);
            String basedir = "";
            for (int i = 0; i < filePaths.length; i++) {
                compress(new File(filePaths[i]), out, basedir);
            }
            out.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private void compress(File file, ZipOutputStream out, String basedir) {
        /* 判断是目录还是文件 */
        if (file.isDirectory()) {
            System.out.println("压缩:" + basedir + file.getName());
            this.compressDirectory(file, out, basedir);
        } else {
            System.out.println("压缩:" + basedir + file.getName());
            this.compressFile(file, out, basedir);
        }
    }

    /** 压缩一个目录 */
    private void compressDirectory(File dir, ZipOutputStream out, String basedir) {
        if (!dir.exists())
            return;

        File[] files = dir.listFiles();
        for (int i = 0; i < files.length; i++) {
            /* 递归 */
            compress(files[i], out, basedir + dir.getName() + "/");
        }
    }

    /** 压缩一个文件 */
    private void compressFile(File file, ZipOutputStream out, String basedir) {
        if (!file.exists())
            return;
        try {
            BufferedInputStream bis = new BufferedInputStream(
                    new FileInputStream(file));
            ZipEntry entry = new ZipEntry(basedir + file.getName());
            out.putNextEntry(entry);
            int count;
            byte data[] = new byte[BUFFER];
            while ((count = bis.read(data, 0, BUFFER)) != -1) {
                out.write(data, 0, count);
            }
            bis.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}