java压缩文件夹(含有空文件夹)

两种实现方式

  • java.util.zip.ZipOutputStream
  • org.apache.tools.ant

注意

最初采用java.util.zip.ZipOutputStream的方式,
jdk为1.8,出现BUG:
一定情况下,会将空文件夹变成文件格式,如:
空目录:鉴定人资格 鉴定人资格证书 鉴定人资格证身份证 文件夹都变成文件了
空目录:鉴定资格证书 鉴定人资格证书啊 都是没问题的
最终改为使用:org.apache.ant 依赖包,得以解决

org.apache.ant 方式

  		<dependency>
            <groupId>org.apache.ant</groupId>
            <artifactId>ant</artifactId>
            <version>1.10.8</version>
        </dependency>
public class ZipApacheUtil {
    private File zipFile;

    /**
     * 压缩文件构造函数
     * @param finalFile 最终压缩生成的压缩文件:目录+压缩文件名.zip
     */
    public ZipApacheUtil(String finalFile) {
        zipFile = new File(finalFile);
    }

    /**
     * 执行压缩操作
     * @param srcPathName 需要被压缩的文件/文件夹
     */
    public void compressExe(String srcPathName) {
        File srcdir = new File(srcPathName);
        if (!srcdir.exists()){
            throw new RuntimeException(srcPathName + "不存在!");
        }

        Project prj = new Project();
        Zip zip = new Zip();
        zip.setProject(prj);
        zip.setDestFile(zipFile);
        FileSet fileSet = new FileSet();
        fileSet.setProject(prj);
        fileSet.setDir(srcdir);
        //fileSet.setIncludes("**/*.java"); //包括哪些文件或文件夹 eg:zip.setIncludes("*.java");
        //fileSet.setExcludes(...); //排除哪些文件或文件夹
        zip.addFileset(fileSet);
        zip.execute();
    }
}

java.util.zip.ZipOutputStream方式

public final class ZIPUtil {
    private ZIPUtil() {

    }

    /**
     * 压缩成ZIP 方法     * @param srcDir 压缩文件夹路径
     *
     * @param out              压缩文件输出流
     * @param keepDirStructure 是否保留原来的目录结构,true:保留目录结构;
     *                         false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
     * @throws RuntimeException 压缩失败会抛出运行时异常
     */
    public static void toZip(String srcDir, OutputStream out, boolean keepDirStructure)
            throws Exception {
        ZipOutputStream zos = null;
        try {
            zos = new ZipOutputStream(out);
            File sourceFile = new File(srcDir);
            compress(sourceFile, zos, sourceFile.getName(), keepDirStructure);
        } catch (Exception e) {
            throw new RuntimeException("zip error from ZipUtil", e);
        } finally {
            if (zos != null) {
               zos.close();
            }
            if (out != null) {
               out.close();
            }
        }

    }

    /**
     * 递归压缩方法
     *
     * @param sourceFile       源文件
     * @param zos              zip输出流
     * @param name             压缩后的名称
     * @param keepDirStructure 是否保留原来的目录结构,true:保留目录结构;
     *                         false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
     * @throws Exception
     */
    private static void compress(File sourceFile, ZipOutputStream zos, String name,
                                 boolean keepDirStructure) throws Exception {
        byte[] buf = new byte[BUFFER_SIZE];
        if (sourceFile.isFile()) {
            // 向zip输出流中添加一个zip实体,构造器中name为zip实体的文件的名字
            zos.putNextEntry(new ZipEntry(name));
            // copy文件到zip输出流中
            int len;
            FileInputStream in = new FileInputStream(sourceFile);
            while ((len = in.read(buf)) != -1) {
                zos.write(buf, 0, len);
            }
            // Complete the entry
            zos.closeEntry();
            in.close();
        } else {
            //是文件夹
            File[] listFiles = sourceFile.listFiles();
            if (listFiles == null || listFiles.length == 0) {
                // 需要保留原来的文件结构时,需要对空文件夹进行处理
                if (keepDirStructure) {
                    // 空文件夹的处理
                    zos.putNextEntry(new ZipEntry(name + "/"));
                    // 没有文件,不需要文件的copy
                    zos.closeEntry();
                }

            } else {
                for (File file : listFiles) {
                    // 判断是否需要保留原来的文件结构
                    if (keepDirStructure) {
                        // 注意:file.getName()前面需要带上父文件夹的名字加一斜杠,
                        // 不然最后压缩包中就不能保留原来的文件结构,即:所有文件都跑到压缩包根目录下了
                        compress(file, zos, name + "/" + file.getName(), keepDirStructure);
                    } else {
                        compress(file, zos, file.getName(), keepDirStructure);
                    }

                }
            }
        }
    }

    /**
     * 创建Zip文件
     *
     * @param fileList    要压缩的文件路径
     * @param zipFileName ZIP压缩包的路径
     * @return ZIP压缩包的路径
     */
    public static String createZipFile(List<String> fileList, String zipFileName) throws IOException {
        if (CollectionUtils.isEmpty(fileList) || StringUtils.isBlank(zipFileName)) {
            return null;
        }
        //构建压缩文件File
        File zipFile = new File(zipFileName);
        //构建ZIP流对象
        try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile))) {
            //循环处理传过来的集合
            for (int i = 0; i < fileList.size(); i++) {
                //获取目标文件
                File inFile = new File(fileList.get(i));
                if (inFile.exists()) {
                    //定义ZipEntry对象
                    ZipEntry entry = new ZipEntry(inFile.getName());
                    //赋予ZIP流对象属性
                    out.putNextEntry(entry);
                    int len = 0;
                    //缓冲
                    byte[] buffer = new byte[1024];
                    //构建FileInputStream流对象
                    try (FileInputStream fis = new FileInputStream(inFile)) {
                        while ((len = fis.read(buffer)) > 0) {
                            out.write(buffer, 0, len);
                            out.flush();
                        }
                    }
                    //关闭closeEntry
                    out.closeEntry();
                }
            }
        }
        return zipFileName;
    }

    /**
     * 创建Zip文件
     *
     * @param contentList 要压缩的文件二进制
     * @return ZIP压缩包二进制
     */
    public static byte[] createZipByte(List<Map<String, Object>> contentList) throws IOException {
        String filePath = CommonConstant.TMP_PATH;
        String zipFileName = "tmp" + DateTools.dateToString(new Date(), DateTools.DF_COMPACT_TIME) + ".zip";
        //构建压缩文件File
        File zipFile = new File(filePath + "/" + zipFileName);
        //构建ZIP流对象
        try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile))) {
            //循环处理传过来的集合
            for (Map<String, Object> map : contentList) {
                String fileName = (String) map.get("fileName");
                byte[] bytes = (byte[]) map.get("byte");
                //定义ZipEntry对象
                ZipEntry entry = new ZipEntry(fileName);
                //赋予ZIP流对象属性
                out.putNextEntry(entry);
                out.write(0);
                out.flush();
                //关闭closeEntry
                out.closeEntry();
            }
        }
        return file2byte(zipFile);
    }

    /**
     * 将文件File转换成byte数组
     *
     * @param tradeFile
     * @return
     */
    private static byte[] file2byte(File tradeFile) throws IOException {
        byte[] buffer = null;
        try (FileInputStream fis = new FileInputStream(tradeFile);
             ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            byte[] b = new byte[1024];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            buffer = bos.toByteArray();
        }
        Files.delete(tradeFile.toPath());
        return buffer;
    }
}

版权声明:本文为qq_38949960原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。