使用的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; } } }