經常伺服器需要對檔案進行壓縮,網路上流傳較多的是從磁碟檔案中來壓縮成zip檔案。但是常常伺服器的檔案存放在記憶體中,以byte[]形式儲存在記憶體中。這個時候就不能使用網路上流傳的常用方法了,這裡就需要對記憶體檔案進行壓縮。通過記憶體檔案來壓縮成zip的方式,首先效能方面比磁碟壓縮要快很多,另外記憶體檔案壓縮到方式不會產生臨時檔案或者磁碟檔案,而磁碟讀取檔案方式壓縮,會產生新的zip檔案。然後要說下的是,記憶體壓縮方式可以支援記憶體檔案壓縮,也可以手動將磁碟檔案讀取到記憶體然後在進行壓縮,這樣也不會產生新的臨時檔案。
該工具類支援加密和非加密兩種壓縮方式
以下貼上我的程式碼
自己擴充套件的記憶體壓縮程式碼
ZipUtils.java
package com.cigna.hmc.groupinsurance.utils; import java.io.IOException; import org.apache.commons.lang.StringUtils; import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.io.ZipOutputStream;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants; /**
*
* @author josnow
* @date 2017年5月24日 下午3:12:31
* @version 1.0.0
* @desc zip工具整合原CompressUtil方法,增加了對記憶體檔案和流檔案的壓縮以避免產生臨時檔案
*/
public class ZipUtils extends CompressUtil { /**
*
* @desc 將記憶體檔案寫入zip內。注意:最後必須呼叫closeZipOutputStream關閉輸出流,或者手動關閉
* @auth josnow
* @date 2017年5月24日 下午5:23:02
* @param fileName
* 檔名
* @param data
* 檔案資料
* @param password
* 密碼
*/
public static void addFileToZip(String fileName, byte[] data, String password, ZipOutputStream zipOutputStream)
throws ZipException, IOException { if (StringUtils.isEmpty(fileName) || data == null || data.length == 0 || zipOutputStream == null) {
throw new ZipException(new StringBuilder("引數異常,fileName=").append(fileName).append(",data=").append(data)
.append(",zipOutputStream=").append(zipOutputStream).toString());
} ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); // 壓縮方式
zipParameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL); // 壓縮級別 zipParameters.setFileNameInZip(fileName); if (StringUtils.isNotBlank(password)) {
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD);
zipParameters.setPassword(password.toCharArray());
} // 原始檔是否為外部流,true表示使用記憶體檔案而非本地儲存檔案
zipParameters.setSourceExternalStream(true); zipOutputStream.putNextEntry(null, zipParameters);
zipOutputStream.write(data);
zipOutputStream.closeEntry();
} /**
*
* @desc 將記憶體檔案寫入zip內。注意:最後必須呼叫closeZipOutputStream關閉輸出流,或者手動關閉
* @auth josnow
* @date 2017年5月24日 下午5:46:02
* @param fileName
* 檔名
* @param data
* 檔案資料
*/
public static void addFileToZip(String fileName, byte[] data, ZipOutputStream zipOutputStream)
throws ZipException, IOException {
addFileToZip(fileName, data, null, zipOutputStream);
} /**
*
* @desc 將記憶體檔案寫入zip內。注意:最後必須呼叫closeZipOutputStream關閉輸出流,或者手動關閉
* @auth josnow
* @date 2017年5月25日 上午11:08:56
* @param zipParameters
* zip引數
* @param data
* 檔案資料
* @param zipOutputStream
* 輸出流
*/
public static void addFileToZip(ZipParameters zipParameters, byte[] data, ZipOutputStream zipOutputStream)
throws ZipException, IOException { if (zipParameters == null || data == null || data.length == 0 || zipOutputStream == null) {
throw new ZipException(new StringBuilder("引數異常,zipParameters=").append(zipParameters).append(",data=")
.append(data).append(",zipOutputStream=").append(zipOutputStream).toString());
}
zipOutputStream.putNextEntry(null, zipParameters);
zipOutputStream.write(data);
zipOutputStream.closeEntry();
} /**
*
* @desc 關閉流
* @auth josnow
* @date 2017年5月25日 上午11:16:01
* @param zipOutputStream
* 輸出流
*/
public static void closeZipOutputStream(ZipOutputStream zipOutputStream) throws IOException, ZipException {
if (zipOutputStream == null) {
return;
}
zipOutputStream.finish();
zipOutputStream.close();
} // public static void main(String[] args) throws Exception {
// ByteArrayOutputStream byteArrayOutputStream = new
// ByteArrayOutputStream(1024);
// ZipOutputStream zipOutputStream = new
// ZipOutputStream(byteArrayOutputStream);
//
// byte[] b = "德瑪西亞哦哦奧法額外發撒旦;聯發科就;".getBytes();
//
// addFileToZip("你好大豬頭.txt", b, zipOutputStream);
// addFileToZip("你就是大肥豬.txt", b, "123", zipOutputStream);
//
// closeZipOutputStream(zipOutputStream);
//
// byte[] zipData = byteArrayOutputStream.toByteArray();
// System.out.println(new String(zipData));
//
// new FileOutputStream("D:\\nima.zip").write(zipData);
// } }
CompressUtil.java 網路上流傳的壓縮工具類
package com.cigna.hmc.groupinsurance.utils; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import org.apache.commons.lang.StringUtils; import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants; /**
* ZIP壓縮檔案操作工具類 支援密碼 依賴zip4j開源專案(http://www.lingala.net/zip4j/) 版本1.3.1
*
* @author ninemax
*/
public class CompressUtil { /**
* 使用給定密碼解壓指定的ZIP壓縮檔案到指定目錄
* <p>
* 如果指定目錄不存在,可以自動建立,不合法的路徑將導致異常被丟擲
*
* @param zip
* 指定的ZIP壓縮檔案
* @param dest
* 解壓目錄
* @param passwd
* ZIP檔案的密碼
* @return 解壓後文件陣列
* @throws ZipException
* 壓縮檔案有損壞或者解壓縮失敗丟擲
*/
public static File[] unzip(String zip, String dest, String passwd) throws ZipException {
File zipFile = new File(zip);
return unzip(zipFile, dest, passwd);
} /**
* 使用給定密碼解壓指定的ZIP壓縮檔案到當前目錄
*
* @param zip
* 指定的ZIP壓縮檔案
* @param passwd
* ZIP檔案的密碼
* @return 解壓後文件陣列
* @throws ZipException
* 壓縮檔案有損壞或者解壓縮失敗丟擲
*/
public static File[] unzip(String zip, String passwd) throws ZipException {
File zipFile = new File(zip);
File parentDir = zipFile.getParentFile();
return unzip(zipFile, parentDir.getAbsolutePath(), passwd);
} /**
* 使用給定密碼解壓指定的ZIP壓縮檔案到指定目錄
* <p>
* 如果指定目錄不存在,可以自動建立,不合法的路徑將導致異常被丟擲
*
* @param zip
* 指定的ZIP壓縮檔案
* @param dest
* 解壓目錄
* @param passwd
* ZIP檔案的密碼
* @return 解壓後文件陣列
* @throws ZipException
* 壓縮檔案有損壞或者解壓縮失敗丟擲
*/
public static File[] unzip(File zipFile, String dest, String passwd) throws ZipException {
ZipFile zFile = new ZipFile(zipFile);
zFile.setFileNameCharset("GBK");
if (!zFile.isValidZipFile()) {
throw new ZipException("壓縮檔案不合法,可能被損壞.");
}
File destDir = new File(dest);
if (destDir.isDirectory() && !destDir.exists()) {
destDir.mkdir();
}
if (zFile.isEncrypted()) {
zFile.setPassword(passwd.toCharArray());
}
zFile.extractAll(dest); List<FileHeader> headerList = zFile.getFileHeaders();
List<File> extractedFileList = new ArrayList<File>();
for (FileHeader fileHeader : headerList) {
if (!fileHeader.isDirectory()) {
extractedFileList.add(new File(destDir, fileHeader.getFileName()));
}
}
File[] extractedFiles = new File[extractedFileList.size()];
extractedFileList.toArray(extractedFiles);
return extractedFiles;
} /**
* 壓縮指定檔案到當前資料夾
*
* @param src
* 要壓縮的指定檔案
* @return 最終的壓縮檔案存放的絕對路徑,如果為null則說明壓縮失敗.
*/
public static String zip(String src) {
return zip(src, null);
} /**
* 使用給定密碼壓縮指定檔案或資料夾到當前目錄
*
* @param src
* 要壓縮的檔案
* @param passwd
* 壓縮使用的密碼
* @return 最終的壓縮檔案存放的絕對路徑,如果為null則說明壓縮失敗.
*/
public static String zip(String src, String passwd) {
return zip(src, null, passwd);
} /**
* 使用給定密碼壓縮指定檔案或資料夾到當前目錄
*
* @param src
* 要壓縮的檔案
* @param dest
* 壓縮檔案存放路徑
* @param passwd
* 壓縮使用的密碼
* @return 最終的壓縮檔案存放的絕對路徑,如果為null則說明壓縮失敗.
*/
public static String zip(String src, String dest, String passwd) {
return zip(src, dest, true, passwd);
} /**
* 使用給定密碼壓縮指定檔案或資料夾到指定位置.
* <p>
* dest可傳最終壓縮檔案存放的絕對路徑,也可以傳存放目錄,也可以傳null或者"".<br />
* 如果傳null或者""則將壓縮檔案存放在當前目錄,即跟原始檔同目錄,壓縮檔名取原始檔名,以.zip為字尾;<br />
* 如果以路徑分隔符(File.separator)結尾,則視為目錄,壓縮檔名取原始檔名,以.zip為字尾,否則視為檔名.
*
* @param src
* 要壓縮的檔案或資料夾路徑
* @param dest
* 壓縮檔案存放路徑
* @param isCreateDir
* 是否在壓縮檔案裡建立目錄,僅在壓縮檔案為目錄時有效.<br />
* 如果為false,將直接壓縮目錄下檔案到壓縮檔案.
* @param passwd
* 壓縮使用的密碼
* @return 最終的壓縮檔案存放的絕對路徑,如果為null則說明壓縮失敗.
*/
public static String zip(String src, String dest, boolean isCreateDir, String passwd) {
File srcFile = new File(src);
dest = buildDestinationZipFilePath(srcFile, dest);
ZipParameters parameters = new ZipParameters();
parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); // 壓縮方式
parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL); // 壓縮級別
if (!StringUtils.isEmpty(passwd)) {
parameters.setEncryptFiles(true);
parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD); // 加密方式
parameters.setPassword(passwd.toCharArray());
}
try {
ZipFile zipFile = new ZipFile(dest);
if (srcFile.isDirectory()) {
// 如果不建立目錄的話,將直接把給定目錄下的檔案壓縮到壓縮檔案,即沒有目錄結構
if (!isCreateDir) {
File[] subFiles = srcFile.listFiles();
ArrayList<File> temp = new ArrayList<File>();
Collections.addAll(temp, subFiles);
zipFile.addFiles(temp, parameters);
return dest;
}
zipFile.addFolder(srcFile, parameters);
} else {
zipFile.addFile(srcFile, parameters);
}
return dest;
} catch (ZipException e) {
e.printStackTrace();
}
return null;
} /**
* 構建壓縮檔案存放路徑,如果不存在將會建立 傳入的可能是檔名或者目錄,也可能不傳,此方法用以轉換最終壓縮檔案的存放路徑
*
* @param srcFile
* 原始檔
* @param destParam
* 壓縮目標路徑
* @return 正確的壓縮檔案存放路徑
*/
private static String buildDestinationZipFilePath(File srcFile, String destParam) {
if (StringUtils.isEmpty(destParam)) {
if (srcFile.isDirectory()) {
destParam = srcFile.getParent() + File.separator + srcFile.getName() + ".zip";
} else {
String fileName = srcFile.getName().substring(0, srcFile.getName().lastIndexOf("."));
destParam = srcFile.getParent() + File.separator + fileName + ".zip";
}
} else {
createDestDirectoryIfNecessary(destParam); // 在指定路徑不存在的情況下將其創建出來
if (destParam.endsWith(File.separator)) {
String fileName = "";
if (srcFile.isDirectory()) {
fileName = srcFile.getName();
} else {
fileName = srcFile.getName().substring(0, srcFile.getName().lastIndexOf("."));
}
destParam += fileName + ".zip";
}
}
return destParam;
} /**
* 在必要的情況下建立壓縮檔案存放目錄,比如指定的存放路徑並沒有被建立
*
* @param destParam
* 指定的存放路徑,有可能該路徑並沒有被建立
*/
private static void createDestDirectoryIfNecessary(String destParam) {
File destDir = null;
if (destParam.endsWith(File.separator)) {
destDir = new File(destParam);
} else {
destDir = new File(destParam.substring(0, destParam.lastIndexOf(File.separator)));
}
if (!destDir.exists()) {
destDir.mkdirs();
}
} }