zoukankan      html  css  js  c++  java
  • zip4j实现多线程压缩

    使用的jar包:zip4j_1.3.2.jar
    基本功能:
    针对ZIP压缩文件创建、添加、分卷、更新和移除文件
    (读写有密码保护的Zip文件)
    (支持AES 128/256算法加密)
    (支持标准Zip算法加密)
    (支持zip64格式)
    (支持Store(仅打包,默认不压缩,不过可以手动设置大小)和Deflate压缩方法
    (针对分块zip文件创建和抽出文件)
    (支持编码)
    (进度监控)
    压缩方式(3种):
    static final int COMP_STORE = 0;(仅打包,不压缩) (对应好压的存储)
    static final int COMP_DEFLATE = 8;(默认) (对应好压的标准)
    static final int COMP_AES_ENC = 99;

    压缩级别有5种:(默认0不压缩)级别跟好压软件是对应的;
    static final int DEFLATE_LEVEL_FASTEST = 1;
    static final int DEFLATE_LEVEL_FAST = 3;
    static final int DEFLATE_LEVEL_NORMAL = 5;
    static final int DEFLATE_LEVEL_MAXIMUM = 7;
    static final int DEFLATE_LEVEL_ULTRA = 9;
    加密方式:
    static final int ENC_NO_ENCRYPTION = -1;(默认,没有加密方法,如果采用此字段,会报错”没有提供加密算法”)
    static final int ENC_METHOD_STANDARD = 0;
    static final int ENC_METHOD_AES = 99;
    AES Key Strength:
    (默认-1,也就是ENC_NO_ENCRYPTION)
    static final int AES_STRENGTH_128 = 0x01;
    static final int AES_STRENGTH_192 = 0x02;
    static final int AES_STRENGTH_256 = 0x03;

    从构造方法可以默认情况:
    compressionMethod = Zip4jConstants.COMP_DEFLATE;
    encryptFiles = false;//不设密码
    readHiddenFiles = true;//可见
    encryptionMethod = Zip4jConstants.ENC_NO_ENCRYPTION;//加密方式不加密
    aesKeyStrength = -1;//
    includeRootFolder = true;//
    timeZone = TimeZone.getDefault();//

    **
     * 情景教学压缩操作类
     */
    public class CompressHandler extends Thread {
    
        private Logger logger = Logger.getLogger(CompressHandler.class);
    
        /**
         * 存储目录名和对应目录下的文件地址
         */
        private Map<String, List<ResourceInfo>> resourceMap;
    
        /**
         * 压缩类中的配置文件
         */
        private String configJson;
    
        /**
         * 配置文件map key为压缩包中的文件名,value为文件内容
         */
        Map<String, String> configJsonMap;
    
        /**
         * 回调接口
         */
        private ZipOperate zipOperate;
    
        /**
         * 加密标志
         */
        private boolean encrypt = false;
    
        /**
         * 线程名称
         */
        private String threadName = Thread.currentThread().getName();
    
        /**
         * 取消标志
         */
        private boolean cancelFlag;
    
        public CompressHandler() {
        }
    
        public CompressHandler(Map<String, List<ResourceInfo>> resourceMap, Map<String, String> configJsonMap, ZipOperate zipOperate) {
            this(resourceMap, configJsonMap, zipOperate, false);
        }
    
        public CompressHandler(Map<String, List<ResourceInfo>> resourceMap, Map<String, String> configJsonMap, ZipOperate zipOperate, boolean encrypt) {
            this.resourceMap = resourceMap;
            this.configJsonMap = configJsonMap;
            this.zipOperate = zipOperate;
            this.encrypt = encrypt;
        }
    
        public CompressHandler(Map<String, List<ResourceInfo>> resourceMap, String configJson, ZipOperate zipOperate) {
            this(resourceMap, configJson, zipOperate, false);
        }
    
        public CompressHandler(Map<String, List<ResourceInfo>> resourceMap, String configJson, ZipOperate zipOperate, boolean encrypt) {
            this.resourceMap = resourceMap;
            this.configJson = configJson;
            this.zipOperate = zipOperate;
            this.encrypt = encrypt;
        }
    
        @Override
        public void run() {
            if (zipOperate != null) {
                zipOperate.beforeCompress();
            }
            String fileName = UUID.randomUUID().toString().replace("-", "").concat(".zip");
            String tempDir = SuperdiamondConfig.getConfig(SuperdiamondConfig.SYSTEM_TMMP_FILE_PATH);
            File tempDirFile = new File(tempDir);
            if (!tempDirFile.exists()) {
                tempDirFile.mkdir();
            }
            String filePath = tempDir.concat("/").concat(fileName);
            //存储生成本地压缩包的文件
            List<File> encryptFileList = new ArrayList<>();
            try {
                ZipFile zipFile = new ZipFile(filePath);
                logger.info("线程" + threadName + "  开始压缩,压缩的文件名为:" + fileName);
                long startTime = System.currentTimeMillis();
                logger.info("线程" + threadName + "  开始时间为:" + startTime);
                ZipParameters parameters = new ZipParameters();
                //设置压缩方式和压缩级别
                parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
                parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
                //当开启压缩包密码加密时
                boolean dirEncrypt = false;
                if (encrypt || Boolean.parseBoolean(SuperdiamondConfig.getConfig(SuperdiamondConfig.ENABLE_ENCRYPT_ZIP))) {
                    logger.info("线程" + threadName + "  该压缩包需要加密");
                    addEncryptParameters(parameters);
                    dirEncrypt = true;
                }
                for (String dir : resourceMap.keySet()) {
                    logger.info("线程" + threadName + "  添加目录:" + dir);
                    List<ResourceInfo> resourceInfoList = resourceMap.get(dir);
                    for (ResourceInfo resourceInfo : resourceInfoList) {
                        String resourceFileName = resourceInfo.getFileName();
                        logger.info("线程" + threadName + "  添加文件:" + resourceFileName);
                        /**
                         * 20180921判断目录名是否为空字符串 true不创建目录 by lizhang10
                         */
                        if(StringUtils.isNotEmpty(dir)){
                            parameters.setFileNameInZip(dir + "/" + resourceFileName);
                        }else{
                            parameters.setFileNameInZip(resourceFileName);
                        }
                        parameters.setSourceExternalStream(true);
                        InputStream inputStream = resourceInfo.getInputStream();
                        if (inputStream == null) {
                            //获取文件流
                            String fileUrl = resourceInfo.getFileUrl();
                            long startTime1 = System.currentTimeMillis();
                            logger.info("线程" + threadName + "  开始获取文件流,地址:" + fileUrl + "  开始时间:" + startTime1);
                            inputStream = getInputStream(fileUrl);
                            long endTime1 = System.currentTimeMillis();
                            logger.info("线程" + threadName + "  结束获取文件流,地址:" + fileUrl + "  结束时间:" + endTime1 + "  耗时毫秒: " + (endTime1 - startTime1));
                        }
                        //当压缩包没有加密时,则从文件属性中取是否进行加密
                        if(!dirEncrypt && resourceInfo.isEncrypt()){
                            //如果是zip的话,则对文件进行解压,然后再加密
                            if(resourceFileName.endsWith(".zip")){
                                long saveStartTime = System.currentTimeMillis();
                                //网络文件路径
                                String sourceFileName = tempDir.concat("/").concat(UUID.randomUUID().toString().concat(".zip"));
                                logger.info("线程" + threadName + " 该文件["+resourceFileName+"]是zip且需要加密,开始存到本地,路径为:"+sourceFileName+"开始时间:" + saveStartTime);
                                //加密文件路径
                                String encryptFileName = tempDir.concat("/").concat(UUID.randomUUID().toString().concat(".zip"));
                                File file = new File(sourceFileName);
                                FileOutputStream outputStream = new FileOutputStream(file);
                                byte[] buffer = new byte[8*1024];
                                int len = 0;
                                while ((len = inputStream.read(buffer)) != -1){
                                    outputStream.write(buffer,0,len);
                                }
                                outputStream.close();
                                inputStream.close();
                                long saveEndTime = System.currentTimeMillis();
                                logger.info("线程" + threadName + " 该文件是zip,存到本地完成,结束时间:" + saveEndTime + "  耗时:"+(saveEndTime - saveStartTime));
                                long extractStartTime = System.currentTimeMillis();
                                logger.info("线程" + threadName + " ,开始进行解压加密,开始时间为:" + extractStartTime);
                                ZipFile sourceZipFile = new ZipFile(file);
                                String extractDir = tempDir.concat("/").concat(UUID.randomUUID().toString());
                                sourceZipFile.extractAll(extractDir);
                                long extractEndTime = System.currentTimeMillis();
                                ZipFile encryptZipFile = new ZipFile(encryptFileName);
                                ZipParameters parameters2 = new ZipParameters();
                                //设置压缩方式和压缩级别
                                parameters2.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
                                parameters2.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
                                addEncryptParameters(parameters2);
                                //添加获取文件的文件和目录
                                File[] fileArray = new File(extractDir).listFiles();
                                for (File file1 : fileArray) {
                                    if(file1.isDirectory()){
                                        encryptZipFile.addFolder(file1,parameters2);
                                    } else {
                                        encryptZipFile.addFile(file1,parameters2);
                                    }
                                }
                                if(!StringUtils.isEmpty(resourceInfo.getConfigJson())){
                                    parameters2.setFileNameInZip("config.json");
                                    parameters2.setSourceExternalStream(true);
                                    encryptZipFile.addStream(new ByteArrayInputStream(resourceInfo.getConfigJson().getBytes("utf8")),parameters2);
                                }
                                logger.info("线程" + threadName + " ,完成解压加密,结束时间为:" + extractEndTime + " 耗时: " + (extractEndTime-extractStartTime));
                                //删除文件
                                sourceZipFile.getFile().delete();
                                //删除目录下的文件
                                deleteFolder(new File(extractDir));
                                File encryptFile = encryptZipFile.getFile();
                                inputStream = new FileInputStream(encryptFile);
                                encryptFileList.add(encryptFile);
                            }
                        }
                        //获取需要打包的文件流
                        zipFile.addStream(inputStream, parameters);
                        inputStream.close();
                    }
                }
                parameters.setSourceExternalStream(true);
                //如果configJsonMap不为空,且length不为0,则遍历加入到压缩包中
                if (configJsonMap != null && configJsonMap.size() > 0) {
                    for (String resourceName : configJsonMap.keySet()) {
                        logger.info("线程" + threadName + " 添加配置文件" + resourceName);
                        parameters.setFileNameInZip(resourceName);
                        String value = configJsonMap.get(resourceName);
                        zipFile.addStream(new ByteArrayInputStream(value.getBytes("utf8")), parameters);
                    }
                }
                if (!StringUtils.isEmpty(configJson)) {
                    logger.info("线程" + threadName + "  添加文件config.json");
                    parameters.setFileNameInZip("config.json");
                    zipFile.addStream(new ByteArrayInputStream(configJson.getBytes("utf8")), parameters);
                }
                logger.info("线程" + threadName + "  压缩文件" + fileName + "完成");
                long endTime = System.currentTimeMillis();
                logger.info("线程" + threadName + "  结束时间为:" + endTime + "  耗时毫秒:" + (endTime - startTime));
                long startTime2 = System.currentTimeMillis();
                logger.info("线程" + threadName + "  开始将压缩包上传到文件服务.......开始时间:" + startTime2);
                FileInfo fileInfo = new CystrageUtil().uploadToRemoteServer(fileName, filePath, null);
                long endTime2 = System.currentTimeMillis();
                logger.info("线程" + threadName + "  上传完成.......结束时间:" + endTime2 + "耗时毫秒:  " + (endTime2 - startTime2));
                if (cancelFlag){
                    throw new InterruptedException("线程" + threadName + "  取消压缩");
                }
                //如果传入了后续操作接口,则将文件服务返回的类传入
                if (zipOperate != null) {
                    zipOperate.afterCompress(fileInfo, zipFile);
                    zipFile.getFile().delete();
                }
            } catch (Exception e) {
                logger.error("线程" + threadName + "  文件压缩出错...........文件内容:" + configJson, e);
                if (zipOperate != null) {
                    zipOperate.errorCompress();
                }
                //删除对应压缩包
                new File(filePath).delete();
            } finally {
                try {
                    //关流
                    inputStream.close();
                } catch (IOException e) {
                    inputStream = null;
                }
                //删除本地生成的压缩文件
                //存储生成本地压缩包的文件
                for (File file : encryptFileList) {
                    file.delete();
                }
            }
        }
    
        /**
         * 删除文件夹下的所有文件
         * @param sourceDir
         */
        private void deleteFolder(File sourceDir) {
            if(sourceDir.isDirectory()){
                File[] files = sourceDir.listFiles();
                for (File file : files) {
                    deleteFolder(file);
                }
            } else {
                sourceDir.delete();
            }
            sourceDir.delete();
        }
    
        private void addEncryptParameters(ZipParameters parameters) {
            String password = SuperdiamondConfig.getConfig(SuperdiamondConfig.ZIP_COMPRESS_PASSWORD);
            parameters.setEncryptFiles(true);
            parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES);
            parameters.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256);
            parameters.setPassword(password.toCharArray());
        }
    
    
        /**
         * 获取输入流
         *
         * @param fileUrl
         * @return
         */
        InputStream inputStream;
    
        private InputStream getInputStream(String fileUrl) throws Exception {
            if(cancelFlag){
                throw new InterruptedException("线程" + threadName + "  取消压缩");
            }
            int retry = 1;
            while (retry <= 3) {
                try {
                    int index = fileUrl.lastIndexOf("/");
                    String prefix = fileUrl.substring(0, index + 1);
                    String fileName = fileUrl.substring(index + 1);
                    URL url = new URL(prefix + URLEncoder.encode(fileName, "utf8"));
                    URLConnection connection = url.openConnection();
                    connection.setDoInput(true);
                    inputStream = connection.getInputStream();
                    return inputStream;
                } catch (Exception e) {
                    if (retry == 1) {
                        logger.error("线程" + threadName + "  获取文件出错,文件地址:" + fileUrl, e);
                    }
                    logger.error("开始重试第" + retry + "次");
                    //由于测试环境服务器承载能力比较差,当获取失败后,睡眠一段时间再重试
                    if(Boolean.parseBoolean(SuperdiamondConfig.getConfig(SuperdiamondConfig.SYSTEM_TEST_ENVIRONMENT))){
                        Thread.currentThread().sleep(Long.parseLong(SuperdiamondConfig.getConfig(SuperdiamondConfig.SYSTEM_SLEEP_TIME)));
                    }
                    if (retry == 3) {
                        throw new Exception(e);
                    }
                    retry++;
                }
            }
            return null;
        }
    
        public void setCancelFlag(Boolean cancelFlag){
            this.cancelFlag = cancelFlag;
        }
    
        @Override
        public void interrupt() {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    inputStream = null;
                    logger.info("线程" + threadName + "  关闭io流失败");
                }
            }
            super.interrupt();
        }
    
        public static class ResourceInfo {
            /**
             * 文件名称
             */
            private String fileName;
    
            /**
             * 文件地址
             */
            private String fileUrl;
    
            /**
             * 输入流
             */
            private InputStream inputStream;
    
            /**
             * 是否要为当前文件添加config,json
             */
            private String configJson;
    
            /**
             * 改文件是否加密
             */
            private boolean encrypt;
    
            public InputStream getInputStream() {
                return inputStream;
            }
    
            public void setInputStream(InputStream inputStream) {
                this.inputStream = inputStream;
            }
    
            public String getFileName() {
                return fileName;
            }
    
            public void setFileName(String fileName) {
                this.fileName = fileName;
            }
    
            public String getFileUrl() {
                return fileUrl;
            }
    
            public void setFileUrl(String fileUrl) {
                this.fileUrl = fileUrl;
            }
    
            public boolean isEncrypt() {
                return encrypt;
            }
    
            public void setEncrypt(boolean encrypt) {
                this.encrypt = encrypt;
            }
    
            public String getConfigJson() {
                return configJson;
            }
    
            public void setConfigJson(String configJson) {
                this.configJson = configJson;
            }
        }
    }
  • 相关阅读:
    python单线程,多线程和协程速度对比
    python redis模块的常见的几个类 Redis 、StricRedis和ConnectionPool
    saltstack安装部署以及简单实用
    python编码详解--转自(Alex的博客)
    老铁,这年头不会点Git真不行!!!
    个人阅读&个人总结
    提问回顾
    结对项目
    个人作业Week3-案例分析
    个人作业Week2-代码复审
  • 原文地址:https://www.cnblogs.com/AnonymouL/p/9700368.html
Copyright © 2011-2022 走看看