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