package com.ruoyi.common.utils.file;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 文件夹压缩成zip文件
 */
public class Folder2ZipUtils {
    /**
     * zip打包
     *
     * @param sourceFileName 资源文件名称
     * @param response 响应头
     */
    public static void zip(String sourceFileName, HttpServletResponse response) {
        ZipOutputStream zipOut = null;
        BufferedOutputStream bOs = null;

        try {
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
            String time = format.format(new Date());
            String downloadFileName = time + "_my.zip";
            // 转换为中文否则可能乱码
            downloadFileName = URLEncoder.encode(downloadFileName, "utf-8");

            // 将zip以流的形式输出到前台 指明response的返回对象是文件流
            response.setHeader("content-type", "application/octet-stream");
            response.setCharacterEncoding("utf-8");
            // 设置浏览器响应头对呀的Content-disposition 设置在下载框默认显示的文件名
            response.setHeader("Content-disposition", "attachment;filename=" + downloadFileName);
            // 创建ZIP输出流
            zipOut = new ZipOutputStream(response.getOutputStream());
            // 创建缓冲输出流
            bOs = new BufferedOutputStream(zipOut);
            File file = new File(sourceFileName);
            // 调用压缩函数
            compress(zipOut, bOs, file, file.getName());
            zipOut.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (zipOut != null) {
                    zipOut.close();
                }
                if (bOs != null) {
                    bOs.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 压缩函数
     *
     * @param zipOut ZIP流
     * @param bOs 缓冲流
     * @param sourceFile 资源文件
     * @param base 根路径
     */
    public static void compress(ZipOutputStream zipOut, BufferedOutputStream bOs, File sourceFile, String base) {
        FileInputStream fOs = null;
        BufferedInputStream bIs = null;
        try {
            // 判断路径是否为目录
            if (sourceFile.isDirectory()) {
                // 取出文件夹中的文件(或子文件夹)
                File[] files = sourceFile.listFiles();
                if (files == null) {
                    throw new RuntimeException("【ZIP工具类】文件夹不存在");
                }
                if (files.length == 0) {
                    // 如果文件夹为空, 则只需在目的地zip文件中写入一个目录进入点
                    zipOut.putNextEntry(new ZipEntry(base + "/"));
                } else {
                    // 如果文件夹不为空，则递归调用compress对文件夹中每一个文件(或文件夹)进行压缩
                    for (File file : files) {
                        compress(zipOut, bOs, file, base + "/" + file.getName());
                    }
                }
            } else {
                // 如果不是目录，即为文件，则先写入目录进入点，再将文件写入zip文件中
                zipOut.putNextEntry(new ZipEntry(base));
                fOs = new FileInputStream(sourceFile);
                bIs = new BufferedInputStream(fOs);

                int tag;
                // 将源文件写入到zip文件中
                while ((tag = bIs.read()) != -1) {
                    zipOut.write(tag);
                }
                bIs.close();
                fOs.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (bIs != null) {
                    bIs.close();
                }
                if (fOs != null) {
                    fOs.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
