zip壓縮檔案處理方案(Zip4j壓縮和解壓)
阿新 • • 發佈:2018-11-11
主要特性
- Create, Add, Extract, Update, Remove files from a Zip file針對ZIP壓縮檔案建立、新增、抽出、更新和移除檔案
- Read/Write password protected Zip files(讀寫有密碼保護的Zip檔案)
- Supports AES 128/256 Encryption(支援AES 128/256演算法加密)
- Supports Standard Zip Encryption(支援標準Zip演算法加密)
- Supports Zip64 format(支援zip64格式)
- Supports Store (No Compression) and Deflate compression method(支援Store(非壓縮)和Deflate壓縮方法---不太明白)
- Create or extract files from Split Zip files (Ex: z01, z02,...zip)(針對分塊zip檔案建立和抽出檔案)
- Supports Unicode file names(支援Unicode編碼檔名)Progress Monitor(進度監控)
使用
zip4j預設採用utf-8編碼,支援中文,也支援密碼和多種壓縮演算法,可以說是功能強大,只是簡單的解壓檔案,按照下面幾步
public static void upzip(File zipFile,String dest,String password) { try { ZipFile zFile = new ZipFile(zipFile);//指向壓縮檔案.zip //設定檔名編碼,在gbk系統中需要設定,檔名稱是中文就不會亂碼 zFile.setFileNameCharset("gbk"); if(!zFile.isValidZipFile()) {// 檢查檔案是否合法 throw new Exception("檔名不合法"); } File destFile = new File(dest);//解壓目錄 if(destFile.isDirectory()&&!destFile.exists()) { destFile.mkdirs(); } if(zFile.isEncrypted()) {//如果設定了密碼 zFile.setPassword(password.toCharArray()); } zFile.extractAll(dest);//將檔案輸出到目標目錄 } catch (Exception e) { e.printStackTrace(); } }
注意,如果解壓的檔案中檔名包含中文,一定要設定檔名字符集編碼
zFile.setFileNameCharset("gbk");
對檔名編碼字符集方法的呼叫一定要靠前,必須在isValidZipFile方法前呼叫,因為isValidZipFile方法的呼叫,會去設定檔名的編碼
zFile.isValidZipFile()
zipModel = headerReader.readAllHeaders(this.fileNameCharset);
壓縮和解壓
public class CompressUtil { private static Logger logger = Logger.getLogger(CompressUtil.class); /** * 解壓檔案 * * @param zipFile 壓縮檔案 * @param dest 解壓檔案的存放目錄 * @param password 壓縮檔案的密碼 */ public static void unzip(File zipFile, String dest, String password) { try { ZipFile zFile = new ZipFile(zipFile);// 指向壓縮檔案.zip zFile.setFileNameCharset("gbk");// 設定檔名編碼,在gbk系統中需要設定 if (!zFile.isValidZipFile()) {// 檢查檔案是否合法 throw new Exception("檔名不合法"); } File destFile = new File(dest);// 解壓目錄 if (destFile.isDirectory() && !destFile.exists()) { destFile.mkdirs(); } if (zFile.isEncrypted()) {// 如果設定了密碼 zFile.setPassword(password.toCharArray()); } zFile.extractAll(dest); } catch (Exception e) { e.printStackTrace(); } } /** * 返回的是解壓後的檔案陣列 * * @param zipFile 壓縮檔案路徑 * @param desc 解壓後文件的存放路徑 * @param passwd 密碼 * @param charset 檔名稱編碼 * @return */ public static File[] getFilesByUnzip(File zipFile, String dest, String passwd, String charset) { try { ZipFile zFile = new ZipFile(zipFile); zFile.setFileNameCharset(charset); if (!zFile.isValidZipFile()) { throw new Exception("檔名稱不合法"); } File destFile = new File(dest); if (destFile.isDirectory() && !destFile.exists()) { destFile.mkdirs(); } if (zFile.isEncrypted()) { zFile.setPassword(passwd); } zFile.extractAll(dest); // 獲取檔案列表 List fileHeaders = zFile.getFileHeaders(); List<File> extractFiles = new ArrayList<>(); if (fileHeaders != null && fileHeaders.size() > 0) { for (int i = 0; i < fileHeaders.size(); i++) { FileHeader header = (FileHeader) fileHeaders.get(i); if (header != null) { extractFiles.add(new File(destFile, header.getFileName())); } } } File[] arr = new File[extractFiles.size()]; return extractFiles.toArray(arr); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 使用給定密碼壓縮指定檔案或資料夾到指定位置. dest可傳最終壓縮檔案存放的絕對路徑,也可以傳存放目錄,也可以傳null或者"". * 如果傳null或者""則將壓縮檔案存放在當前目錄,即跟原始檔同目錄,壓縮檔名取原始檔名,以.zip為字尾; * 如果以路徑分隔符(File.separator)結尾,則視為目錄,壓縮檔名取原始檔名,以.zip為字尾,否則視為檔名. * @param src 要壓縮的檔案或資料夾路徑 * @param dest 壓縮檔案存放路徑 * @param isCreateDir 是否在壓縮檔案裡建立目錄,僅在壓縮檔案為目錄時有效. 如果為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 zipParameters = new ZipParameters(); zipParameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);//設定壓縮方法是deflate zipParameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);//設定壓縮級別 if(passwd!=null&&passwd.trim().length()>0) { // 如果密碼不為空,壓縮包進行加密,需要設定壓縮演算法 zipParameters.setEncryptFiles(true); zipParameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD);//加密演算法設定為standard zipParameters.setPassword(passwd.toCharArray()); } try { ZipFile zipFile = new ZipFile(dest); if(srcFile.isDirectory()) { if(!isCreateDir) {//如果false,表示不按照目錄結構進行壓縮 ArrayList<File> list = new ArrayList<>(); Collections.addAll(list, srcFile.listFiles()); zipFile.addFiles(list, zipParameters); }else { //按照目錄結構壓縮 zipFile.addFolder(srcFile, zipParameters); } }else { zipFile.addFile(srcFile, zipParameters); } } catch (ZipException e) { logger.error("-----檔案壓縮失敗-----"); logger.error(e.getMessage()); dest = null; } return dest; } /** * 構建壓縮檔案存放路徑,如果不存在將會建立 * 傳入的可能是檔名或者目錄,也可能不傳,此方法用以轉換最終壓縮檔案的存放路徑 * * @param srcFile 原始檔 * @param destParam 壓縮目標路徑 * * @return 正確的壓縮檔案存放路徑 */ private static String buildDestinationZipFilePath(File srcFile, String destParam) { if (destParam == null || destParam.trim() == "") { 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 file = null; if(destParam.endsWith(File.separator)) { file = new File(destParam); }else { file = new File(destParam.substring(0, destParam.lastIndexOf(File.separator))); } if(file.exists()) { file.mkdirs(); } } }
刪除
進行刪除操作前, 也要設定檔名編碼為gbk,因為如果是中文名稱的檔案,就會丟擲could not find file header for file的錯誤
刪除檔案
根據檔名稱或者FileHeader刪除
public RemoveFileFromZipFile() {
try {
// Initiate ZipFile object with the path/name of the zip file.
ZipFile zipFile = new ZipFile("d:\\1.zip");
zipFile.setFileNameCharset("gbk");
// Note: If this zip file is a split file then this method throws an exception as
// Zip Format Specification does not allow updating split zip files
// Please make sure that this zip file has more than one file to completely test
// this example
// Removal of a file from a zip file can be done in two ways:
// 1. 直接根據檔名稱刪除
zipFile.removeFile("新建文字文件.txt");
// 2. 建立FileHeader,根據FileHeader刪除
if (zipFile.getFileHeaders() != null && zipFile.getFileHeaders().size() > 0) {
zipFile.removeFile((FileHeader)zipFile.getFileHeaders().get(0));
} else {
System.out.println("This cannot be demonstrated as zip file does not have any files left");
}
} catch (ZipException e) {
e.printStackTrace();
}
刪除目錄
將目錄下面的檔案刪除,在刪除目錄
/**
* 刪除壓縮檔案中的檔案或者目錄
* @param file 壓縮檔案的路徑
* @param removeFile 檔名或者目錄
*/
public static void removeDirFromZip(String file,String removeFile) {
try {
ZipFile zipFile = new ZipFile(file);
zipFile.setFileNameCharset("gbk");//設定檔名的編碼格式
if(!removeFile.endsWith("/")) {
//刪除檔案的方式,第一種是根據檔案的名稱,第二種是根據檔案的fileHeader進行刪除
//zipFile.removeFile(removeFile);
FileHeader header = new FileHeader();
header.setFileName(removeFile);
zipFile.removeFile(header);
}else {
//如果是目錄的話,需要先將目錄下面的檔案刪除掉,在刪除目錄
if(!removeFile.endsWith("/")) removeFile +="/";
List headers = zipFile.getFileHeaders();
List<FileHeader> removeFiles = new ArrayList<>();
for (int i = 0; i < headers.size(); i++) {
FileHeader subHeader =(FileHeader) headers.get(i);
if(subHeader.getFileName().contains(removeFile)
&&!subHeader.getFileName().equals(removeFile)) {
//不能直接刪除,會丟擲java.lang.IndexOutOfBoundsException
// zipFile.removeFile(subHeader);
// 這裡我們使用一個list記錄下刪除的subheader,在進行刪除
removeFiles.add(subHeader);
}
}
for (int i = 0; i < removeFiles.size(); i++) {
zipFile.removeFile(removeFiles.get(i));
}
//最後將目錄刪除
if(zipFile.getFileHeader(removeFile)!=null) {
zipFile.removeFile(removeFile);
}
}
} catch (ZipException e) {
e.printStackTrace();
}
}
參考部落格:https://blog.csdn.net/zhyh1986/article/details/7921376