Java生成Zip格式文件之归档、打包、压缩、解压

问题描述:zip 文件打包与解压是作为程序猿的我们经常会碰到的问题,但是这么常见的功能,还自己一行一行的去码代码,实在是有点浪费时间。上网一搜,满屏幕的 zip 压缩解决工具类,复制下来一运行,各种BUG,烦~~~不过,现在好了,你烦的事情我已经烦过了,所以特意把我烦之后的结果贴出来,减轻各位同学的烦恼。好了,话不多说,上代码。

package com.utility.zip;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

/**
 * Zip 文件工具类
 * 
 * @ClassName: ZipUtil
 * @author Supreme_Sir
 * @date 2020年6月30日 上午10:47:28
 */
public class ZipUtil {
    
    
    /**
     * 缓冲区
     */
    private static final int BUFFER = 2048;

    /**
     * 压缩的文件后缀名
     */
    private static final String SUFFIX = ".zip";

    /**
     * 解压字符集
     */
    private static final String ENCODE = "UTF-8";

    /**
     * 得到源文件路径的所有文件
     * 
     * @Title: getAllFile 
     * @param dirFile 压缩源文件路径 
     * @return List<File> 
     * @throws
     */
    public static List<File> getAllFile(File dirFile) {
    
    
        List<File> fileList = new ArrayList<File>();
        // 判断传入的参数是否为文件夹
        if (dirFile.isDirectory()) {
    
    
            File[] files = dirFile.listFiles();
            // 遍历目标路径下的所有文件
            for (File file : files) {
    
    
                // 判断文件类型,如果是文件则直接添加至结果集合中,如果为文件夹,则递归添加
                if (file.isFile()) {
    
    
                    fileList.add(file);
                } else {
    
    
                    if (file.listFiles().length != 0) {
    
    
                        fileList.addAll(getAllFile(file));
                    } else {
    
    
                        fileList.add(file);
                    }
                }
            }
        } else {
    
    
            fileList.add(dirFile);
        }
        return fileList;
    }

    /**
     * 获取相对路径
     * 
     * @Title: getRelativePath 
     * @param dirPath 源文件路径 
     * @param file 准备压缩的单个文件 
     * @return String 
     * @throws
     */
    public static String getRelativePath(String dirPath, File file) {
    
    
        // 创建源文件所在目录,用以控制路径深度
        File dirFile = new File(dirPath);
        // 获取当前文件的文件名
        String relativePath = file.getName();
        while (true) {
    
    
            // 获取当前文件所在的目录
            file = file.getParentFile();
            if (file == null)
                break;
            // 判断当前文件目录是否为源文件所在目录
            if (file.equals(dirFile)) {
    
    
                break;
            } else {
    
    
                // 拼装相对路径
                relativePath = file.getName() + "/" + relativePath;
            }
        }
        return relativePath;
    }

    /**
     * 将压缩后的文件保存至源文件所在磁盘的根目录
     * 
     * @Title: compress2RootPath 
     * @param dirPath 压缩源文件路径 
     * @throws
     */
    public static void compress2RootPath(String dirPath) {
    
    
        int firstIndex = 0;
        int lastIndex = 0;
        // 判断路径分割符
        if (dirPath.contains("/")) {
    
    
            firstIndex = dirPath.indexOf("/");
            lastIndex = dirPath.lastIndexOf("/");
        } else {
    
    
            firstIndex = dirPath.indexOf("\\");
            lastIndex = dirPath.lastIndexOf("\\");
        }
        // 生成压缩后文件的绝对路径
        String zipFileName = dirPath.substring(0, firstIndex + 1) + dirPath.substring(lastIndex + 1);
        compress2CustomPath(dirPath, zipFileName);
    }

    /**
     * 将指定路径的文件压缩至指定位置
     * 
     * @Title: compress2CustomPath 
     * @param dirPath 压缩源文件路径 
     * @param zipFileName 压缩目标文件路径 
     * void 
     * @throws
     */
    public static void compress2CustomPath(String dirPath, String zipFileName) {
    
    
        zipFileName = zipFileName + SUFFIX;
        File dirFile = new File(dirPath);
        // 获取目标路径下所有的文件
        List<File> fileList = getAllFile(dirFile);
        byte[] buffer = new byte[BUFFER];
        ZipEntry zipEntry = null;
        // 每次读取出来的长度
        int readLength = 0;
        try {
    
    
            // 对输出文件做CRC32校验
            CheckedOutputStream cos = new CheckedOutputStream(new FileOutputStream(zipFileName), 
            	new CRC32());
            ZipOutputStream zos = new ZipOutputStream(cos);
            for (File file : fileList) {
    
    
                // 若是文件,则压缩文件
                if (file.isFile()) {
    
    
                    zipEntry = new ZipEntry(getRelativePath(dirPath, file));
                    zipEntry.setSize(file.length());
                    zipEntry.setTime(file.lastModified());
                    zos.putNextEntry(zipEntry);
                    InputStream is = new BufferedInputStream(new FileInputStream(file));
                    while ((readLength = is.read(buffer, 0, BUFFER)) != -1) {
    
    
                        zos.write(buffer, 0, readLength);
                    }
                    is.close();
                    // 若是空目录,则写入zip条目中
                } else {
    
    
                    zipEntry = new ZipEntry(getRelativePath(dirPath, file));
                    zos.putNextEntry(zipEntry);
                }
            }
            // 最后得关闭流,不然压缩最后一个文件会出错
            zos.close();
        } catch (FileNotFoundException e) {
    
    
            e.printStackTrace();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }

    /**
     * 解压Zip文件
     * 
     * @param path                    文件目录
     * @param explorerIntoCurrentPath 是否解压到当前目录 
     *                  true:解压到文件所在目录 
     *                  false:解压到压缩包同名文件夹内
     */
    public static void decompress(String path, boolean explorerIntoCurrentPath) {
    
    
        int count = -1;
        File file = null;
        InputStream is = null;
        FileOutputStream fos = null;
        BufferedOutputStream bos = null;
        // 初始化文件保存路径
        String savepath = path.substring(0, path.lastIndexOf("\\")) + File.separator;
        // 判断是否解压到文件所在目录
        if (!explorerIntoCurrentPath) {
    
    
            // 重置文件保存路径
            savepath = path.substring(0, path.lastIndexOf(".")) + File.separator;
            // 创建保存目录
            new File(savepath).mkdir();
        }
        ZipFile zipFile = null;
        try {
    
    
            // 解决中文乱码问题
            zipFile = new ZipFile(path, Charset.forName(ENCODE));
            // 获取压缩包内文件集合
            Enumeration<?> entries = zipFile.entries();
            while (entries.hasMoreElements()) {
    
    
                byte buf[] = new byte[BUFFER];
                ZipEntry entry = (ZipEntry) entries.nextElement();
                // 获取当前文件
                String filename = entry.getName();
                // 是否需要创建文件夹标识
                boolean ismkdir = false;
                int fileSeparatorIndex = filename.lastIndexOf("/");
                // 检查此文件是否需要创建文件夹
                if (fileSeparatorIndex != -1 && 
                	!new File(savepath + filename.substring(0, fileSeparatorIndex)).exists()) {
    
    
                    ismkdir = true;
                }
                filename = savepath + filename;
                file = new File(filename);
                // 如果需要创建文件夹,则先创建文件夹
                if (ismkdir) {
    
    
                    new File(filename.substring(0, filename.lastIndexOf("/"))).mkdirs();
                }
                // 创建文件
                file.createNewFile();
                is = zipFile.getInputStream(entry);
                fos = new FileOutputStream(file);
                bos = new BufferedOutputStream(fos, BUFFER);
                while ((count = is.read(buf)) > -1) {
    
    
                    bos.write(buf, 0, count);
                }
                bos.flush();
                bos.close();
                fos.close();
                is.close();
            }
            zipFile.close();
        } catch (IOException ioe) {
    
    
            ioe.printStackTrace();
        } finally {
    
    
            try {
    
    
                if (bos != null) {
    
    
                    bos.close();
                }
                if (fos != null) {
    
    
                    fos.close();
                }
                if (is != null) {
    
    
                    is.close();
                }
                if (zipFile != null) {
    
    
                    zipFile.close();
                }
            } catch (Exception e) {
    
    
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
    
    
        compress2RootPath("F:\\头像 - 副本.jpeg");
        decompress("F:\\ant.zip", false);
    }
}

上面的代码,是博主从茫茫代码中搜集后整理的结果,已完成基本BUG的修复和关键逻辑的注释。

主要功能:

  1. 支持文件压缩
  2. 支持文件夹压缩
  3. 支持自定义文件解压路径
  4. 默认将文件解压至所在磁盘根目录

-------------------- 懂事后,开始不去为了读书而读书,而是在书中读自己,在书中发现自己,或检查自己。 --------------------

猜你喜欢

转载自blog.csdn.net/Supreme_Sir/article/details/107042768
今日推荐