欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java生成zip压缩文件

程序员文章站 2022-06-07 15:21:58
...
jdk自身有zip相关的代码,不过直到1.6的版本没有提供设置字符集的接口,因此都会出现中文乱码,目前网上的方案大多需要引入ant包进行处理:

//创建org.apache.tools.zip.ZipOutputStream
ZipOutputStream zos = new ZipOutputStream(cos);
zos.setEncoding("gbk");


然而,1.7已经修复了这个问题

在jdk7中的java.util.zip.ZipOutputStream新增了这样一个构造方法:
    /**
     * Creates a new ZIP output stream.
     *
     * @param out the actual output stream
     *
     * @param charset the {@linkplain java.nio.charset.Charset charset}
     *                to be used to encode the entry names and comments
     *
     * @since 1.7
     */
    public ZipOutputStream(OutputStream out, Charset charset) {
        super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
        if (charset == null)
            throw new NullPointerException("charset is null");
        this.zc = ZipCoder.get(charset);
        usesDefaultDeflater = true;
    }

这就为我们设置字符集提供了接口

ZipOutputStream zos = new ZipOutputStream(cos, Charset.forName("gbk"));


这样一来两个方法基本来说可以算是等效了,后面的新增文件方法都相同的
给一个使用jdk自带ZipOutputStream的直接取得zip文件字节数组的方案


import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.Charset;
import java.util.HashSet;
import java.util.Set;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * Created with IntelliJ IDEA.
 * User: yixian
 * Date: 13-10-17
 * Time: 下午2:52
 * 将文件夹压缩并取回zip文件byte[]
 */
public class DefaultZipper implements IZipper {
    private Set<String> filePathSet = new HashSet<String>();
    private File targetFile;
    private Logger logger = LoggerFactory.getLogger(getClass());

    public DefaultZipper() {
        String tempDirectory = FileUtils.getTempDirectoryPath();
        if (!tempDirectory.endsWith(File.separator)) {
            tempDirectory += File.separator;
        }
        targetFile = initRandomTarget(tempDirectory);
    }

    private synchronized File initRandomTarget(String tempDirectory) {
        File target;
        do {
            String fileName = RandomStringUtils.random(20, true, true);
            String targetFilePath = tempDirectory + fileName;
            target = new File(targetFilePath);
        } while (target.exists());
        return target;
    }

    private boolean checkFilePath(String path) {
        File file = new File(path);
        return file.exists();
    }

    @Override
    public boolean addFile(String filePath) {
        if (checkFilePath(filePath)) {
            filePathSet.add(filePath);
            return true;
        }
        return false;
    }

    @Override
    public String[] addFiles(String... paths) {
        String[] notExistsFiles = new String[0];
        for (String path : paths) {
            if (!addFile(path)) {
                ArrayUtils.add(notExistsFiles, path);
            }
        }
        return notExistsFiles;
    }

    @Override
    public byte[] doCompress() throws IOException {
        FileOutputStream fos = new FileOutputStream(targetFile);
        CheckedOutputStream cos = new CheckedOutputStream(fos, new CRC32());
        ZipOutputStream zos = new ZipOutputStream(cos, Charset.forName("gbk"));
        String baseDir = "";
        for (String filePath : filePathSet) {
            compress(new File(filePath), zos, baseDir);
        }
        zos.close();
        return loadTargetFileBytes();
    }

    private void compress(File file, ZipOutputStream zos, String basePath) {
        if (file.isDirectory()) {
            logger.debug("compressing dir:" + basePath + file.getName());
            compressDirectory(file, zos, basePath);
        } else {
            logger.debug("compressing file:" + basePath + file.getName());
            compressFile(file, zos, basePath);
        }
    }

    private void compressDirectory(File dir, ZipOutputStream zos, String basePath) {
        File[] childrenFiles = dir.listFiles();
        for (File child : childrenFiles != null ? childrenFiles : new File[0]) {
            compress(child, zos, basePath + dir.getName() + "/");
        }
    }

    private void compressFile(File file, ZipOutputStream zos, String basePath) {
        if (!file.exists()) {
            return;
        }
        try {
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
            String entryName = basePath + file.getName();
            ZipEntry entry = new ZipEntry(entryName);
            zos.putNextEntry(entry);
            byte[] buffer = FileUtils.readFileToByteArray(file);
            zos.write(buffer);
            zos.flush();
            zos.closeEntry();
            bis.close();
        } catch (IOException ignored) {
        }
    }

    private byte[] loadTargetFileBytes() {
        try {
            byte[] fileBytes = FileUtils.readFileToByteArray(targetFile);
            boolean deleted = targetFile.delete();
            logger.debug("file:" + targetFile.getAbsoluteFile() + " deleted:" + deleted);
            return fileBytes;
        } catch (IOException e) {
            return new byte[0];
        }
    }
}



引入了两个commons包,给出Maven Dependency
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>


测试:
import com.skytech.crius.city.util.DefaultZipper;
import org.junit.Test;

import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Created with IntelliJ IDEA.
 * User: yixian
 * Date: 13-10-21
 * Time: 上午10:30
 */
public class ZipTest {
    private static final String SOURCE_FILE_PATH = "d:\\foo\\bar";
    @Test
    public void DefaultZipperTest() throws IOException {
        IZipper zipper = new DefaultZipper();
        zipper.addFile(SOURCE_FILE_PATH);
        byte[] bytes = zipper.doCompress();
        FileOutputStream fos = new FileOutputStream("d:\\test.zip");
        fos.write(bytes);
        fos.flush();
        fos.close();
    }
}


注意这个案例因为要把zip压缩文件整体读入内存所以如果压的文件体积太大就会......
相关标签: java zip