Java Zip 基于磁盘实现压缩和解压 附可用工具类

欢迎大家关注本博,同时欢迎大家评论交流,可以给个赞哦!!!

  Zip是常用的无损压缩算法实现,Java中提供了Zip的实现,本文演示基于磁盘的方式进行压缩和解压,演示只针对一层目录结构进行,多层目录只需递归操作进行即可。

  文中提供完整的工具类,以供大家使用。

  Maven依赖

  ant: ant: 1.8.0:JDK1.7以下版本环境下,JDK原生的ZIP流处理会出现中文条目乱码的问题,此依赖提供了ZIP相关的流实现, 可以完美的解决低版本JDK出现的问题。JDK1.7及JDK1.7+版本上已无此问题。

  commons-io: commons-io: 2.4: JDK原生的流操作是比较繁琐的,例如:流的开闭处理、流的转换处理等,会使得代码无序且凌乱。commons-io针对IO操作提供了良好的封装,可以使用简单的操作完成繁杂的处理,commons-io本身已经对IO做了相对完善的封装。

<dependency>
	<groupId>ant</groupId>
	<artifactId>ant</artifactId>
	<version>1.8.0</version>
</dependency>
<dependency>
	<groupId>commons-io</groupId>
	<artifactId>commons-io</artifactId>
	<version>2.4</version>
</dependency>
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

  工具类

  其实,在通常情况下,我们都是在磁盘上进行压缩和解压操作的,这样虽然增加了操作的复杂度,但是却无形中避免了一些问题。

  下面是提供的ZIP算法实现的工具类,提供了compressByZip、compressByZipJdkLower7、decompressByZip三个方法,在无特殊需求的情况下,基本可以满足压缩和解压的需求,代码如下:

package com.arhorchin.securitit.compress.zip;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;

/**
 * @author Securitit.
 * @note 基于磁盘以ZIP算法进行压缩和解压工具类.
 */
public class ZipDiskUtil {
    
    

    /**
     * logger.
     */
    private static Logger logger = Logger.getLogger(ZipDiskUtil.class);

    /**
     * 条目名称使用的默认字符.
     */
    public final static String CHARSET_GBK = "GBK";

    /**
     * 使用ZIP算法进行压缩.
     * @param sourceFolderPath 待进行压缩的文件夹路径.
     * @param targetZipFilePath 压缩后的ZIP文件存储目录.
     * @return 压缩是否成功.
     * @throws Exception 压缩过程中可能发生的异常,若发生异常,则不会生成ZIP文件.
     */
    public static boolean compressByZip(String sourceFolderPath, String targetZipFilePath) throws Exception {
    
    
        // 变量定义.
        File sourceFolderFile = null;
        ZipOutputStream zipZos = null;
        FileOutputStream zipFos = null;
        InputStream singleFileIs = null;
        File[] sourceFilesInFolder = null;

        try {
    
    
            // 取得待压缩文件列表.
            sourceFolderFile = new File(sourceFolderPath);
            sourceFilesInFolder = sourceFolderFile.listFiles();
            // 压缩文件变量初始化.
            zipFos = new FileOutputStream(new File(targetZipFilePath));
            zipZos = new ZipOutputStream(zipFos);
            // 将文件添加到ZIP条目中.
            for (File singleFile : sourceFilesInFolder) {
    
    
                zipZos.putNextEntry(new ZipEntry(singleFile.getName()));
                singleFileIs = new FileInputStream(singleFile);
                IOUtils.copy(singleFileIs, zipZos);
            }
        } catch (Exception ex) {
    
    
            logger.info("ZipDiskUtil.compressByZip.", ex);
            return false;
        } finally {
    
    
            if (null != singleFileIs)
                singleFileIs.close();
            if (null != zipZos)
                zipZos.close();
            if (null != zipFos)
                zipFos.close();
        }
        return true;
    }

    /**
     * 使用ZIP算法进行压缩.JDK1.7版本一下,对中文处理不是很友好,可以使用这个方法解决.
     * @param sourceFolderPath 待进行压缩的文件夹路径.
     * @param targetZipFilePath 压缩后的ZIP文件存储目录.
     * @return 压缩是否成功.
     * @throws Exception 压缩过程中可能发生的异常,若发生异常,则不会生成ZIP文件.
     */
    public static boolean compressByZipJdkLower7(String sourceFolderPath, String targetZipFilePath) throws Exception {
    
    
        return compressByZipJdkLower7(sourceFolderPath, targetZipFilePath, CHARSET_GBK);
    }

    /**
     * 使用ZIP算法进行压缩.JDK1.7版本一下,对中文处理不是很友好,可以使用这个方法解决.
     * @param sourceFolderPath 待进行压缩的文件夹路径.
     * @param targetZipFilePath 压缩后的ZIP文件存储目录.
     * @param charset 压缩条目使用的字符集.
     * @return 压缩是否成功.
     * @throws Exception 压缩过程中可能发生的异常,若发生异常,则不会生成ZIP文件.
     */
    public static boolean compressByZipJdkLower7(String sourceFolderPath, String targetZipFilePath, String charset)
            throws Exception {
    
    
        // 变量定义.
        File sourceFolderFile = null;
        FileOutputStream zipFos = null;
        InputStream singleFileIs = null;
        File[] sourceFilesInFolder = null;
        org.apache.tools.zip.ZipOutputStream zipZos = null;

        try {
    
    
            // 取得待压缩文件列表.
            sourceFolderFile = new File(sourceFolderPath);
            sourceFilesInFolder = sourceFolderFile.listFiles();
            // 压缩文件变量初始化.
            zipFos = new FileOutputStream(new File(targetZipFilePath));
            zipZos = new org.apache.tools.zip.ZipOutputStream(zipFos);
            // 设置条目名称编码.
            zipZos.setEncoding(charset);
            // 将文件添加到ZIP条目中.
            for (File singleFile : sourceFilesInFolder) {
    
    
                zipZos.putNextEntry(new org.apache.tools.zip.ZipEntry((singleFile.getName())));
                singleFileIs = new FileInputStream(singleFile);
                IOUtils.copy(singleFileIs, zipZos);
            }
        } catch (Exception ex) {
    
    
            logger.info("ZipDiskUtil.compressByZipJdkLower7.", ex);
            return false;
        } finally {
    
    
            if (null != singleFileIs)
                singleFileIs.close();
            if (null != zipFos)
                zipFos.close();
            if (null != zipZos)
                zipZos.close();
        }
        return true;
    }

    /**
     * 使用ZIP算法进行解压.
     * @param sourceZipPath 待解压文件路径.
     * @param targetFolderPath 解压后文件夹目录.
     * @return 解压是否成功.
     * @throws Exception 解压过程中可能发生的异常,若发生异常,则不会生成文件夹.
     */
    public static boolean decompressByZip(String sourceZipPath, String targetFolderPath) throws Exception {
    
    
        // 变量定义.
        ZipEntry singleZipEntry;
        String zipEntryName = null;
        ZipInputStream zipZis = null;
        FileInputStream zipFis = null;
        BufferedInputStream zipBis = null;

        try {
    
    
            // 解压变量初始化.
            zipFis = new FileInputStream(new File(sourceZipPath));
            zipBis = new BufferedInputStream(zipFis);
            zipZis = new ZipInputStream(zipBis);
            // 条目解压缩至指定文件夹目录下.
            while ((singleZipEntry = zipZis.getNextEntry()) != null) {
    
    
                zipEntryName = singleZipEntry.getName();
                FileUtils.writeByteArrayToFile(new File(targetFolderPath + File.separator + zipEntryName),
                        IOUtils.toByteArray(zipZis));
            }
        } catch (Exception ex) {
    
    
            logger.info("ZipDiskUtil.decompressByZip.", ex);
            return false;
        } finally {
    
    
            if (null != zipFis)
                zipFis.close();
            if (null != zipZis)
                zipZis.close();
            if (null != zipBis)
                zipBis.close();
        }
        return true;
    }

}

  工具类测试

  在Maven依赖引入正确的情况下,复制上面的代码到项目中,修改package,可以直接使用,下面我们对工具类进行简单测试。测试类代码如下:

package com.arhorchin.securitit.compress.zip;

import com.arhorchin.securitit.compress.zip.ZipDiskUtil;

/**
 * @author Securitit.
 * @note ZipDiskUtil工具类测试.
 */
public class ZipDiskUtilTester {
    
    

    public static void main(String[] args) throws Exception {
    
    
        ZipDiskUtil.compressByZip("C:/Users/Administrator/Downloads/个人文件/2020-07-13/files", "C:/Users/Administrator/Downloads/个人文件/2020-07-13/disk.zip");
        ZipDiskUtil.decompressByZip("C:/Users/Administrator/Downloads/个人文件/2020-07-13/disk.zip", "C:/Users/Administrator/Downloads/个人文件/2020-07-13-01/disk");
    }

}

  运行测试后,通过查看disk.zip和解压的目录,可以确认工具类运行结果无误。

  总结

  1) 在小文件、文件数量较小且较为固定时,提倡使用基于内存压缩和解压方式。使用内存换时间,减少频繁的磁盘操作。可以参见《Java Zip 基于内存实现压缩和解压》

  2) 在大文件、文件数量较大时,提倡使用基于磁盘压缩和解压方式。过大文件对服务会造成过度的负载,磁盘压缩和解压可以缓解这种压力。

  3) JDK1.6及以下版本中,JDK提供的java.util.zip.*进行压缩时,对于中文条目名称处理会出现乱码,需要额外引用Ant包,使用其org.apache.tools.zip.*来解决这个问题。

本博微信公众号“超哥说码”,欢迎大家订阅,公众号正在完善中,会及时将更优质的博文推送于您!
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/securitit/article/details/108151494