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;
        }
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM