package com.fdkankan.common.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import it.sauronsoftware.jave.*;
import org.apache.commons.lang3.ObjectUtils;
import org.bytedeco.javacpp.opencv_core;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Decoder;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLDecoder;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;

public class FileUtils {

    private static Logger log = LoggerFactory.getLogger(FileUtils.class);

    public static byte[] getImageByte(String base64Data){
        byte[] bt = null;
        try {
            sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
            if (base64Data.startsWith("data:image/png;base64,")) {
                return decoder.decodeBuffer(base64Data.replace("data:image/png;base64,", ""));
            } else if (base64Data.startsWith("data:image/jpeg;base64,")) {
                return decoder.decodeBuffer(base64Data.replace("data:image/jpeg;base64,", ""));
            } else if (base64Data.startsWith("data:image/bmp;base64,")) {
                return decoder.decodeBuffer(base64Data.replace("data:image/bmp;base64,", ""));
            } else {
                return bt;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bt;
    }

    public static void uploadImg(String path, String base64Data){
        byte[] bt = getImageByte(base64Data);
        writeBinary(bt, path);
    }

    private static void writeBinary(byte[] buf, String filePath) {
        FileUtil.writeBytes(buf,filePath);
    }
	
	public static boolean createDir(String destDirName) {
        FileUtil.mkdir(destDirName);
        return true;
    }

    /**
     * 创建文件
     * @param fileName  文件名称
     * @param fileContent   文件内容
     * @return  是否创建成功，成功则返回true
     */
    public static boolean createFile(String path, String fileName,String fileContent){
        String fileNameTemp = path+fileName+".json";//文件路径+名称+文件类型
        File file = new File(fileNameTemp);
        if(!file.exists()){
            FileUtil.appendUtf8String(fileContent,fileNameTemp);
            log.info("success create file:{}",fileNameTemp);
            return true;
        }
        return false;
    }
    
    /**
     * 向文件中写入内容
     * @param filePath 文件路径与名称
     * @param newstr  写入的内容
     * @return
     * @throws IOException
     */
    public static boolean writeFileContent(String filePath, String newstr) throws IOException{
        Boolean bool = false;
        String filein = newstr+"\r\n";//新写入的行，换行
        String temp  = "";
        
        FileInputStream fis = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
        FileOutputStream fos  = null;
        PrintWriter pw = null;
        try {
            File file = new File(filePath);//文件路径(包括文件名称)
            //将文件读入输入流
            fis = new FileInputStream(file);
            isr = new InputStreamReader(fis);
            br = new BufferedReader(isr);
            StringBuffer buffer = new StringBuffer();
            
            //文件原有内容
            for(int i=0;(temp =br.readLine())!=null;i++){
                buffer.append(temp);
                // 行与行之间的分隔符 相当于“\n”
                buffer = buffer.append(System.getProperty("line.separator"));
            }
            buffer.append(filein);
            
            fos = new FileOutputStream(file);
            pw = new PrintWriter(fos);
            pw.write(buffer.toString().toCharArray());
            pw.flush();
            bool = true;
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }finally {
            //不要忘记关闭
            if (pw != null) {
                pw.close();
            }
            if (fos != null) {
                fos.close();
            }
            if (br != null) {
                br.close();
            }
            if (isr != null) {
                isr.close();
            }
            if (fis != null) {
                fis.close();
            }
        }
        return bool;
    }
    
    /**
     * 删除单个文件
     *
     * @param fileName
     *            要删除的文件的文件名
     * @return 单个文件删除成功返回true，否则返回false
     */
    public static boolean deleteFile(String fileName) {
        File file = new File(fileName);
        if (file.exists() && file.isFile()) {
            if (file.delete()) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
    
    /** 
     *  根据路径删除指定的目录，无论存在与否 
     *@param sPath  要删除的目录path 
     *@return 删除成功返回 true，否则返回 false。 
     */  
    public static boolean deleteFolder(String sPath) {
        boolean flag = false;
        File file = new File(sPath);
        // 判断目录或文件是否存在
        if (!file.exists()) {  // 不存在返回 false
            return flag;
        } else {
            // 判断是否为文件
            if (file.isFile()) {  // 为文件时调用删除文件方法
                return deleteFile(sPath);
            } else {  // 为目录时调用删除目录方法
                return deleteDirectory(sPath);
            }
        }
    }
    
    /**
     * 删除目录以及目录下的文件
     * @param   dirPath 被删除目录的路径
     * @return  目录删除成功返回true，否则返回false
     */
    public static boolean deleteDirectory(String dirPath) {
        FileUtil.del(dirPath);
        return true;
    }

    //按行读文件
    public static String readFile(String path) {
        try {
            if(!FileUtil.exist(path)){
                log.warn("文件不存在，path:{}", path);
                return null;
            }
            return FileUtil.readUtf8String(path);
        } catch (IORuntimeException e) {
            log.error("读取文件失败,文件不存在,path:"+path, e);
        }
        return null;
    }

    public static boolean copyFile(String srcFileName, String destFileName, boolean overlay) {
        FileUtil.copy(srcFileName,destFileName,overlay);
        return true;
    }


    // 复制文件
    public static void copyFile(File sourceFile,File targetFile){
        FileUtil.copy(sourceFile,targetFile,true);
    }

    public static void copyFolderAllFiles(String srcFolder, String destFolder, boolean overlay) {
        log.info("开始拷贝文件内容：src:{},target:{}",srcFolder,destFolder);
        FileUtil.copyContent(new File(srcFolder),new File(destFolder),overlay);
        log.info("拷贝文件结束，src:{},target:{}",srcFolder,destFolder);
    }


    // 复制文件夹
    public static void copyDirectiory(String sourceDir, String targetDir)
            throws IOException {
        if(!new File(sourceDir).exists()){
            return;
        }
        // 新建目标目录
        (new File(targetDir)).mkdirs();
        // 获取源文件夹当前下的文件或目录
        File[] file = (new File(sourceDir)).listFiles();
        for (int i = 0; i < file.length; i++) {
            if (file[i].isFile()) {
                // 源文件
                File sourceFile=file[i];
                // 目标文件
                File targetFile=new
                        File(new File(targetDir).getAbsolutePath()
                        +File.separator+file[i].getName());
                copyFile(sourceFile,targetFile);
            }
            if (file[i].isDirectory()) {
                // 准备复制的源文件夹
                String dir1=sourceDir + "/" + file[i].getName();
                // 准备复制的目标文件夹
                String dir2=targetDir + "/"+ file[i].getName();
                copyDirectiory(dir1, dir2);
            }
        }
    }

    /**
     * 从网络Url中下载文件
     *
     * @param urlStr
     * @param fileName
     * @param savePath
     * @return
     * @throws IOException
     */
    public static boolean downLoadFromUrl(String urlStr, String fileName, String savePath){
        HttpUtil.downloadFile(urlStr,savePath + File.separator + fileName);
        return true;
    }

    public static byte[] getBytesFromUrl(String urlStr){
        return HttpUtil.downloadBytes(urlStr);
    }


    public static String getStringFromUrl(String urlStr){
        return HttpUtil.downloadString(urlStr, StandardCharsets.UTF_8);
    }

    /**
     * 从输入流中获取字节数组
     *
     * @param inputStream
     * @return
     * @throws IOException
     */
    private static byte[] readInputStream(InputStream inputStream) throws IOException {
        byte[] buffer = new byte[1024];
        int len = 0;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        while ((len = inputStream.read(buffer)) != -1) {
            bos.write(buffer, 0, len);
        }
        bos.close();
        return bos.toByteArray();
    }

    public static void writeFile(String filePath,String str){
        if(!new File(filePath).getParentFile().exists()){
            new File(filePath).getParentFile().mkdirs();
        }
        FileUtil.writeString(str,filePath,StandardCharsets.UTF_8);
    }

    /**
     * 将byte数组写入文件
     *
     * @param path
     * @param fileName
     * @param content
     * @throws IOException
     */
    public static void writeFile(String path, String fileName, byte[] content){
        FileUtil.writeBytes(content,path + fileName);
    }

    /**
     * 向json文件写入参数,重复的覆盖，多的新增
     * @return
     */
    public static void writeJsonFile(String path, Map<String, Object> map){
        File file = new File(path);
        JSONObject json = new JSONObject();
        if(file.exists()){
            json = JSONObject.parseObject(FileUtil.readUtf8String(path));
        }
        json.putAll(map);
        FileUtils.writeFile(path,json.toJSONString());
    }

    public static void decompress(String srcPath, String dest){
        ZipUtil.unzip(srcPath,dest);
    }

    public static void zipFile(String zipFileName, String inputFileName){
        ZipUtil.zip(inputFileName,zipFileName);
    }

    //删除文件夹
    public static void delFolder(String folderPath) {
        FileUtil.del(folderPath);
    }

    //删除指定文件夹下的所有文件
    public static boolean delAllFile(String path) {
        FileUtil.del(path);
        return true;
    }

    public static List<String> readfileNamesForDirectory(String path, String except) {
        try {
            File file = new File(path);
            if (file.isDirectory()) {
                String[] fileNames = file.list();
                List<String> list = new ArrayList<String>();
                if (fileNames != null) {
                    for (int i = 0; i < fileNames.length; ++i) {
                        if (fileNames[i].toLowerCase().endsWith(except)) {
                            list.add(fileNames[i]);
                        }
                    }
                }
                return list;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //递归获取文件中所有文件的路径
    public static List<String> readfilePath(String path, List<String> urlList) {
        try{
            File file = new File(path);
            if(file != null && file.isDirectory()) {
                File[] files = file.listFiles();

                if(files != null) {
                    for(int i=0;i<files.length;++i) {
                        if(files[i].isDirectory()){
                            readfilePath(files[i].getAbsolutePath(), urlList);
                        }else {
                            urlList.add(files[i].getAbsolutePath());
                        }
                    }
                }
                return urlList;
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        return urlList;
    }

    public static void saveImageToDisk(String accessToken, String mediaId, String picName, String picPath,InputStream inputStream){
        byte[] data = new byte[10240];
        int len = 0;
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(picPath+picName+".amr");
            while ((len = inputStream.read(data)) != -1) {
                fileOutputStream.write(data, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //音频转换（To Mp3）
    public static void changeVoiceToMp3(String sourcePath,String targetPath){
        File source = new File(sourcePath);
        File target = new File(targetPath);
        if(target.exists())
        {
            target.delete();
        }
        AudioAttributes audio = new AudioAttributes();
        Encoder encoder = new Encoder();
        audio.setChannels(2);
        audio.setCodec("libmp3lame");
        EncodingAttributes attrs = new EncodingAttributes();
        attrs.setFormat("mp3");
        attrs.setAudioAttributes(audio);

        try {
            encoder.encode(source, target, attrs);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InputFormatException e) {
            e.printStackTrace();
        } catch (EncoderException e) {
            e.printStackTrace();
        }
    }


    /**
     * 获取指定视频的帧并保存为图片至指定目录
     * @param filePath 视频存放的地址
     * @param targerFilePath 截图存放的地址
     * @param targetFileName 截图保存的文件名称
     * @return
     * @throws Exception
     */
    public static boolean executeCodecs(String filePath, String targerFilePath, String targetFileName){
        try{
            FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath);
            ff.start();
            String rotate =ff.getVideoMetadata("rotate");
            Frame f;
            int i = 0;
            while (i <1) {
                f =ff.grabImage();
                opencv_core.IplImage src = null;
                if(null !=rotate &&rotate.length() > 1) {
                    OpenCVFrameConverter.ToIplImage converter =new OpenCVFrameConverter.ToIplImage();
                    src =converter.convert(f);
                    f =converter.convert(rotate(src, Integer.valueOf(rotate)));
                }
                doExecuteFrame(f,targerFilePath,targetFileName);
                i++;
            }
            ff.stop();
            return true;
        }catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }

    /*
     * 旋转角度的
     */
    public static opencv_core.IplImage rotate(opencv_core.IplImage src, int angle) {
        opencv_core.IplImage img = opencv_core.IplImage.create(src.height(), src.width(), src.depth(), src.nChannels());
        opencv_core.cvTranspose(src, img);
        opencv_core.cvFlip(img, img, angle);
        return img;
    }


    public static void doExecuteFrame(Frame f, String targerFilePath, String targetFileName) {

        if (null ==f ||null ==f.image) {
            return;
        }
        Java2DFrameConverter converter =new Java2DFrameConverter();
        String imageMat ="jpg";
        String FileName =targerFilePath + File.separator +targetFileName +"." +imageMat;
        BufferedImage bi =converter.getBufferedImage(f);
        System.out.println("width:" + bi.getWidth());//打印宽、高
        System.out.println("height:" + bi.getHeight());
        File output =new File(FileName);
        try {
            ImageIO.write(bi,imageMat,output);
        }catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取音频时长
     * @throws IOException
     */
    public static long getAudioPlayTime(File source){
        Encoder encoder = new Encoder();
        long ls = 0;
        try {
            MultimediaInfo m = encoder.getInfo(source);
            ls = m.getDuration();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return ls;
    }

    public static void pngToJpg(String pngPath, String jpgPath){
        try {
            //1.读取本地png图片or读取url图片
            File input = new File(pngPath);
            BufferedImage bimg = ImageIO.read(input);//读取本地图片
            //BufferedImage bimg = ImageIO.read(new URL("http://img.alicdn.com/tfs/TB1kbMoUOLaK1RjSZFxXXamPFXa.png"));//读取url图片

            //2. 填充透明背景为白色
            BufferedImage res = new BufferedImage(bimg.getWidth(), bimg.getHeight(), BufferedImage.TYPE_INT_RGB);
            res.createGraphics().drawImage(bimg, 0, 0, Color.WHITE, null); //背景填充色设置为白色，也可以设置为其他颜色比如粉色Color.PINK

            //3. 保存成jpg到本地
            File output = new File(jpgPath);
            ImageIO.write(res, "jpg", output);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static List<String> list(File file) throws Exception{
        List<String> keys = new ArrayList<>();
        //判断file是否是目录
        if(file.isDirectory()){
            File [] lists = file.listFiles();
            if(lists!=null){
                for(int i=0;i<lists.length;i++)
                {
                    keys.addAll(list(lists[i]));//是目录就递归进入目录内再进行判断
                }
            }
        }else{
            keys.add(file.getAbsolutePath());
        }
        return keys;
    }


    /**
     *
     * @param content base64内容
     * @param path 输出文件路径，需要后缀名
     * @return
     */
    public static  boolean base64ToFileWriter(String content, String path) {
        if (content == null) {
            return false;
        }
        BASE64Decoder decoder = new BASE64Decoder();
        try {
            // decoder
            byte[] b = decoder.decodeBuffer(content);
            // processing data
            for (int i = 0; i < b.length; ++i) {
                if (b[i] < 0) {
                    b[i] += 256;
                }
            }
            FileUtil.writeBytes(b,path);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 已移除，请在项目中自行实现
     */
//    public static String getResource(){
//        String path = "";
//        try {
//            path = ResourceUtils.getURL("classpath:").getPath();
//            path = URLDecoder.decode(path,"utf-8");
//        } catch (Exception e) {
//        }
//        return path;
//    }

    /**
     * 判断文件大小处于限制内
     *
     * @param fileLen 文件长度
     * @param fileSize 限制大小
     * @param fileUnit 限制的单位（B,K,M,G）
     * @return
     */
    public static boolean checkFileSizeIsLimit(Long fileLen, double fileSize, String fileUnit) {
//        long len = file.length();
        double fileSizeCom = 0;
        if ("B".equals(fileUnit.toUpperCase())) {
            fileSizeCom = (double) fileLen;
        } else if ("K".equals(fileUnit.toUpperCase())) {
            fileSizeCom = (double) fileLen / 1024;
        } else if ("M".equals(fileUnit.toUpperCase())) {
            fileSizeCom = (double) fileLen / (1024*1024);
        } else if ("G".equals(fileUnit.toUpperCase())) {
            fileSizeCom = (double) fileLen / (1024*1024*1024);
        }
        if (fileSizeCom > fileSize) {
            return false;
        }
        return true;

    }

    private boolean checkFile(String fileName) {
        //设置允许上传文件类型
        String suffixList = ".jpg,.gif,.png,.ico,.bmp,.jpeg,.zip,.zp,.rar,.mp3,.mp4,.avi,.mov";
        // 获取文件后缀
        String suffix = fileName.substring(fileName.lastIndexOf(".")
                + 1, fileName.length());
        if (suffixList.contains(suffix.trim().toLowerCase())) {
            System.out.println("无非法参数可以放行！！！");
            log.info("无非法参数可以放行！！！");
            return true;
        }
        log.info("存在非法参数不能放行！请核对上传文件格式，重新刷新页面再次上传！");
        return false;
    }

    /**
     * 删除文件
     *
     * @param filePathAndName
     *            String 文件路径及名称 如c:/fqf.txt
     * @return boolean
     */
    public static void delFile(String filePathAndName) {
        FileUtil.del(filePathAndName);
    }

    /**
     * 读取到字节数组0
     *
     * @param filePath //路径
     * @throws IOException
     */
    public static byte[] getContent(String filePath) throws IOException {
        File file = new File(filePath);
        long fileSize = file.length();
        if (fileSize > Integer.MAX_VALUE) {
            System.out.println("file too big...");
            return null;
        }
        FileInputStream fi = new FileInputStream(file);
        byte[] buffer = new byte[(int) fileSize];
        int offset = 0;
        int numRead = 0;
        while (offset < buffer.length
                && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {
            offset += numRead;
        }
        // 确保所有数据均被读取
        if (offset != buffer.length) {
            throw new IOException("Could not completely read file "
                    + file.getName());
        }
        fi.close();
        return buffer;
    }

    /**
     * 读取到字节数组1
     *
     * @param filePath
     * @return
     * @throws IOException
     */
    public static byte[] toByteArray(String filePath) throws IOException {

        File f = new File(filePath);
        if (!f.exists()) {
            throw new FileNotFoundException(filePath);
        }
        ByteArrayOutputStream bos = new ByteArrayOutputStream((int) f.length());
        BufferedInputStream in = null;
        try {
            in = new BufferedInputStream(new FileInputStream(f));
            int buf_size = 1024;
            byte[] buffer = new byte[buf_size];
            int len = 0;
            while (-1 != (len = in.read(buffer, 0, buf_size))) {
                bos.write(buffer, 0, len);
            }
            return bos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            bos.close();
        }
    }

    /**
     * 读取到字节数组2
     *
     * @param filePath
     * @return
     * @throws IOException
     */
    public static byte[] toByteArray2(String filePath) throws IOException {

        File f = new File(filePath);
        if (!f.exists()) {
            throw new FileNotFoundException(filePath);
        }

        FileChannel channel = null;
        FileInputStream fs = null;
        try {
            fs = new FileInputStream(f);
            channel = fs.getChannel();
            ByteBuffer byteBuffer = ByteBuffer.allocate((int) channel.size());
            while ((channel.read(byteBuffer)) > 0) {
                // do nothing
                // System.out.println("reading");
            }
            return byteBuffer.array();
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            try {
                channel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                fs.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Mapped File way MappedByteBuffer 可以在处理大文件时，提升性能
     *
     * @param filePath
     * @return
     * @throws IOException
     */
    public static byte[] toByteArray3(String filePath) throws IOException {

        FileChannel fc = null;
        RandomAccessFile rf = null;
        try {
            rf = new RandomAccessFile(filePath, "r");
            fc = rf.getChannel();
            MappedByteBuffer byteBuffer = fc.map(FileChannel.MapMode.READ_ONLY, 0,
                    fc.size()).load();
            //System.out.println(byteBuffer.isLoaded());
            byte[] result = new byte[(int) fc.size()];
            if (byteBuffer.remaining() > 0) {
                // System.out.println("remain");
                byteBuffer.get(result, 0, byteBuffer.remaining());
            }
            return result;
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            try {
                rf.close();
                fc.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static File[] sort(File[] s) {
        return Arrays.stream(s).sorted(Comparator.comparingInt(o -> Integer.parseInt(FileUtil.mainName(o)))).collect(Collectors.toList()).toArray(new File[]{});
    }

    /**
     * 获取目录下所有文件
     * @param directory
     */
    public static List<String> getFileList(String directory) {

        File f = new File(directory);

        File[] files = f.listFiles();

        if(files == null || files.length == 0){
            return null;
        }

        List<String> list = new ArrayList<>();
        for (int i = 0; i < files.length; i++) {

            if (files[i].isFile()) {
                list.add(files[i].getAbsolutePath());
            } else {
                System.out.println("目录：" + files[i]);
                List<String> fileList = getFileList(files[i].getAbsolutePath());
                if(CollUtil.isEmpty(fileList)){
                    continue;
                }
                list.addAll(fileList);
            }
        }

        return list;
    }

    /**
     * <p>
     zip包解压缩
     * </p>
     * @author dengsixing
     * @date 2022/2/16
     * @param inputFile 解压文件路径
     * @param destDirPath 解压目标目录
     **/
    public static void unZip(String inputFile,String destDirPath){
        ZipUtil.unzip(inputFile,destDirPath);
    }

    /**
     * <p>
     打包
     * </p>
     * @author dengsixing
     * @date 2022/2/16
     * @param inputFile
     * @param outputFile
     * @param withDir
     **/
    public static void zip(String inputFile, String outputFile, boolean withDir) throws Exception {

        try (
            //创建zip输出流
            java.util.zip.ZipOutputStream out = new java.util.zip.ZipOutputStream(new FileOutputStream(outputFile));
            //创建缓冲输出流
            BufferedOutputStream bos = new BufferedOutputStream(out);
        ) {
            File input = new File(inputFile);
            compress(out, bos, input, null, withDir);
        }
    }

    /**
     * @param name 压缩文件名，可以写为null保持默认
     */
    //递归压缩
    public static void compress(java.util.zip.ZipOutputStream out, BufferedOutputStream bos, File input, String name, boolean withDir) throws IOException {
        if (name == null) {
            name = input.getName();
        }
        //如果路径为目录（文件夹）
        if (input.isDirectory()) {
            //取出文件夹中的文件（或子文件夹）
            File[] flist = input.listFiles();
            if (flist.length == 0) {//如果文件夹为空，则只需在目的地zip文件中写入一个目录进入
                if (withDir) {
                    out.putNextEntry(new java.util.zip.ZipEntry(name + "/"));
                }
            } else {//如果文件夹不为空，则递归调用compress，文件夹中的每一个文件（或文件夹）进行压缩
                for (int i = 0; i < flist.length; i++) {
                    if (withDir) {
                        compress(out, bos, flist[i], name + "/" + flist[i].getName(), withDir);
                    } else {
                        compress(out, bos, flist[i], flist[i].getName(), withDir);
                    }
                }
            }
        } else {//如果不是目录（文件夹），即为文件，则先写入目录进入点，之后将文件写入zip文件中
            out.putNextEntry(new java.util.zip.ZipEntry(name));
            FileInputStream fos = new FileInputStream(input);
            BufferedInputStream bis = new BufferedInputStream(fos);
            int len;
            //将源文件写入到zip文件中
            byte[] buf = new byte[1024];
            while ((len = bis.read(buf)) != -1) {
                bos.write(buf, 0, len);
            }
            bis.close();
            fos.close();
        }
    }

    public static JSONObject readJson(String filePath) throws IOException {
        try {
            if(!FileUtil.exist(filePath)){
                log.warn("文件不存在，path:{}", filePath);
                return null;
            }
            String content = FileUtil.readUtf8String(filePath);
            JSONObject jsonObj = JSON.parseObject(content);
            return jsonObj;
        } catch (Exception e) {
            log.error("读取json失败,filePath:" + filePath, e);
        }
        return null;
    }

    /**
     * utf-8格式读取文件，若文件不存在或者读取文件异常，返回null
     * @param path
     * @return
     */
    public static String readUtf8String(String path){
        try {
            if(!FileUtil.exist(path)){
                log.warn("文件不存在，path:{}", path);
                return null;
            }
            return FileUtil.readUtf8String(path);
        }catch (Exception e){
            log.error("读取文件失败,path:"+path, e);
        }
        return null;
    }

    /**
     * 获取文件数量
     * @param file 文件夹
     * @return
     */
    public static long getSubFileNums(File file) {
        long total = 0L;
        try {
            if (ObjectUtils.isEmpty(file) || !file.exists()) {
                log.error("文件夹不存在");
                return 0;
            }
            File[] subFiles = file.listFiles();
            for (File subFile : subFiles) {
                if (subFile.isFile()) {
                    total++;
                    continue;
                }
                total = total + getSubFileNums(subFile);
            }
        } catch (Exception e) {
            log.error("获取文件数量失败！" , e);
        }
        return total;
    }


}
