檔案壓縮與解壓
阿新 • • 發佈:2021-12-09
JAVA壓縮與解壓
需要的jar包
<dependency>
<groupId>com.github.axet</groupId>
<artifactId>java-unrar</artifactId>
<version>1.7.0-3</version>
</dependency>
package com.util.base; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.channels.FileChannel; import java.nio.charset.Charset; import java.util.Calendar; import java.util.Enumeration; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.CRC32; import java.util.zip.CheckedOutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import de.innosystec.unrar.Archive; import de.innosystec.unrar.NativeStorage; import de.innosystec.unrar.exception.RarException; import de.innosystec.unrar.rarfile.FileHeader; /** * 打包與解壓操作類 * @author zhanglang * 2018-09-26 */ public class ZipUtil { /** * 遞迴壓縮資料夾 * @param srcRootDir 壓縮資料夾根目錄的子路徑 * @param file 當前遞迴壓縮的檔案或目錄物件 * @param zos 壓縮檔案儲存物件 * @throws Exception */ private static void zip(String srcRootDir, File file, ZipOutputStream zos) throws Exception { if (file == null){ return; } //如果是檔案,則直接壓縮該檔案 if (file.isFile()){ int count, bufferLen = 2048; byte data[] = new byte[bufferLen]; //獲取檔案相對於壓縮資料夾根目錄的子路徑 String subPath = file.getAbsolutePath(); int index = subPath.indexOf(srcRootDir); if (index != -1){ subPath = subPath.substring(srcRootDir.length() + File.separator.length()); } ZipEntry entry = new ZipEntry(subPath); zos.putNextEntry(entry); BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); while ((count = bis.read(data, 0, bufferLen)) != -1){ zos.write(data, 0, count); } bis.close(); zos.closeEntry(); } else { //如果是目錄,則壓縮整個目錄 //壓縮目錄中的檔案或子目錄 File[] childFileList = file.listFiles(); if(childFileList != null) { for (int n=0; n<childFileList.length; n++){ childFileList[n].getAbsolutePath().indexOf(file.getAbsolutePath()); zip(srcRootDir, childFileList[n], zos); } } } } /** * 對檔案或檔案目錄進行壓縮 * @param srcPath 要壓縮的原始檔路徑。如果壓縮一個檔案,則為該檔案的全路徑;如果壓縮一個目錄,則為該目錄的頂層目錄路徑 * @param zipPath 壓縮檔案儲存的路徑。注意:zipPath不能是srcPath路徑下的子資料夾 * @param zipFileName 壓縮檔名 * @throws Exception */ public static void zip(String srcPath, String zipPath, String zipFileName) throws Exception { if (StringUtils.isEmpty(srcPath) || StringUtils.isEmpty(zipPath) || StringUtils.isEmpty(zipFileName)){ throw new TzException("Parameter null error."); } CheckedOutputStream cos = null; ZipOutputStream zos = null; try{ File srcFile = new File(srcPath); //判斷壓縮檔案儲存的路徑是否為原始檔路徑的子資料夾,如果是,則丟擲異常(防止無限遞迴壓縮的發生) if (srcFile.isDirectory() && zipPath.indexOf(srcPath)!=-1){ throw new TzException("zipPath must not be the child directory of srcPath."); } //判斷壓縮檔案儲存的路徑是否存在,如果不存在,則建立目錄 File zipDir = new File(zipPath); if (!zipDir.exists() || !zipDir.isDirectory()){ zipDir.mkdirs(); } //建立壓縮檔案儲存的檔案物件 String zipFilePath = zipPath + (zipPath.endsWith(File.separator) ? "" : File.separator) + zipFileName; File zipFile = new File(zipFilePath); if (zipFile.exists()){ //檢測檔案是否允許刪除,如果不允許刪除,將會丟擲SecurityException // SecurityManager securityManager = new SecurityManager(); // securityManager.checkDelete(zipFilePath); //刪除已存在的目標檔案 zipFile.delete(); } cos = new CheckedOutputStream(new FileOutputStream(zipFile), new CRC32()); zos = new ZipOutputStream(cos); //如果只是壓縮一個檔案,則需要擷取該檔案的父目錄 String srcRootDir = srcPath; if (srcFile.isFile()){ int index = srcPath.lastIndexOf(File.separator); if (index != -1){ srcRootDir = srcPath.substring(0, index); } } //呼叫遞迴壓縮方法進行目錄或檔案壓縮 zip(srcRootDir, srcFile, zos); zos.flush(); } catch (Exception e){ throw e; } finally { try{ if (zos != null){ zos.close(); } }catch (Exception e){ e.printStackTrace(); } } } /** * 解壓縮zip包 * @param zipFilePath zip檔案的全路徑 * @param unzipFilePath 解壓後的檔案儲存的路徑 */ @SuppressWarnings("unchecked") public static void unZip(String zipFilePath, String unzipFilePath) throws TzException { if (StringUtils.isEmpty(zipFilePath) || StringUtils.isEmpty(unzipFilePath)){ throw new TzException("引數錯誤"); } File zipFile = new File(zipFilePath); if (!zipFile.exists()) { throw new TzException(zipFile.getPath() + "所指檔案不存在"); } //建立解壓縮檔案儲存的路徑 File unzipFileDir = new File(unzipFilePath); if (!unzipFileDir.exists() || !unzipFileDir.isDirectory()){ unzipFileDir.mkdirs(); } if (zipFilePath.toLowerCase().endsWith(".rar")) { unRar(zipFilePath, unzipFilePath); }else { if (!zipFilePath.toLowerCase().endsWith(".zip")) { throw new TzException("檔案不是zip壓縮檔案"); } //開始解壓 int count = 0, bufferSize = 2048; byte[] buffer = new byte[bufferSize]; ZipFile zip = null; try { zip = new ZipFile(zipFile, Charset.forName("GBK")); Enumeration<ZipEntry> entries = (Enumeration<ZipEntry>)zip.entries(); //迴圈對壓縮包裡的每一個檔案進行解壓 while(entries.hasMoreElements()){ ZipEntry entry = entries.nextElement(); if (entry.isDirectory()) { String dirPath = unzipFilePath + File.separator + entry.getName(); File dir = new File(dirPath); //如果資料夾路徑不存在,則建立資料夾 if (!dir.exists()){ dir.mkdirs(); } } else { //構建壓縮包中一個檔案解壓後儲存的檔案全路徑 String entryFilePath = unzipFilePath + File.separator + entry.getName(); //建立解壓檔案 File entryFile = new File(entryFilePath); if (entryFile.exists()){ //檢測檔案是否允許刪除,如果不允許刪除,將會丟擲SecurityException //SecurityManager securityManager = new SecurityManager(); //securityManager.checkDelete(entryFilePath); //刪除已存在的目標檔案 entryFile.delete(); } //寫入檔案 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(entryFile)); BufferedInputStream bis = new BufferedInputStream(zip.getInputStream(entry)); while ((count = bis.read(buffer, 0, bufferSize)) != -1){ bos.write(buffer, 0, count); } //關閉 if(null != bis) bis.close(); if(null != bos){ bos.flush(); bos.close(); } } } } catch (Exception e) { e.printStackTrace(); throw new TzException("解壓失敗", e); } finally { if(zip != null){ try { zip.close(); } catch (IOException e) { e.printStackTrace(); } } } } } /** * 根據原始rar路徑,解壓到指定資料夾下. winrar5.0以上版本壓縮檔案解壓異常 * @param srcRarPath 原始rar路徑 * @param dstDirectoryPath 解壓到的資料夾 * @throws TzException */ public static void unRar(String srcRarPath, String dstDirectoryPath) throws TzException { if (StringUtils.isEmpty(srcRarPath) || StringUtils.isEmpty(dstDirectoryPath)){ throw new TzException("引數錯誤"); } File zipFile = new File(srcRarPath); if (!zipFile.exists()) { throw new TzException(zipFile.getPath() + "所指檔案不存在"); } if (srcRarPath.toLowerCase().endsWith(".zip")) { unZip(srcRarPath, dstDirectoryPath); }else { if (!srcRarPath.toLowerCase().endsWith(".rar")) { throw new TzException("檔案不是rar壓縮檔案"); } File dstDiretory = new File(dstDirectoryPath); if (!dstDiretory.exists()) {// 目標目錄不存在時,建立該資料夾 dstDiretory.mkdirs(); } Archive a = null; FileOutputStream os = null; try { NativeStorage nsFile = new NativeStorage(new File(srcRarPath)); a = new Archive(nsFile); if (a != null) { a.getMainHeader().print(); // 列印檔案資訊. FileHeader fh = a.nextFileHeader(); while (fh != null) { String fileName= fh.getFileNameW().trim(); if(!existZH(fileName)){ fileName = fh.getFileNameString().trim(); } if (fh.isDirectory()) { // 資料夾 File fol = new File(dstDirectoryPath + File.separator + fileName); fol.mkdirs(); } else { // 檔案 File out = new File(dstDirectoryPath + File.separator + fileName.trim()); try {// 之所以這麼寫try,是因為萬一這裡面有了異常,不影響繼續解壓. if (!out.exists()) { if (!out.getParentFile().exists()) {// 相對路徑可能多級,可能需要建立父目錄. out.getParentFile().mkdirs(); } out.createNewFile(); } os = new FileOutputStream(out); a.extractFile(fh, os); os.close(); os = null; } catch (Exception ex) { ex.printStackTrace(); } } fh = a.nextFileHeader(); } a.close(); a = null; } }catch(RarException e) { e.printStackTrace(); throw new TzException("程式不支援該壓縮格式,請將檔案壓縮成rar4或zip格式", e); }catch(Exception e){ e.printStackTrace(); throw new TzException("解壓失敗", e); }finally{ if(os!=null){ try{ os.close(); os=null; }catch(Exception e){ e.printStackTrace(); } } if(a!=null){ try{ a.close(); a=null; }catch(Exception e){ e.printStackTrace(); } } } } } /** * 刪除單個檔案 * @param fileName 要刪除的檔案的檔名 * @return 單個檔案刪除成功返回true,否則返回false */ public static boolean deleteFile(String fileName) { File file = new File(fileName); // 如果檔案路徑所對應的檔案存在,並且是一個檔案,則直接刪除 if (file.exists() && file.isFile()) { if (file.delete()) { System.out.println("刪除單個檔案" + fileName + "成功!"); return true; } else { System.out.println("刪除單個檔案" + fileName + "失敗!"); return false; } } else { System.out.println("刪除單個檔案失敗:" + fileName + "不存在!"); return false; } } /** * 刪除目錄及目錄下的檔案 * @param dir 要刪除的目錄的檔案路徑 * @return 目錄刪除成功返回true,否則返回false */ public static boolean deleteDirectory(String dir) { // 如果dir不以檔案分隔符結尾,自動新增檔案分隔符 if (!dir.endsWith(File.separator)) dir = dir + File.separator; File dirFile = new File(dir); // 如果dir對應的檔案不存在,或者不是一個目錄,則退出 if ((!dirFile.exists()) || (!dirFile.isDirectory())) { System.out.println("刪除目錄失敗:" + dir + "不存在!"); return false; } boolean flag = true; // 刪除資料夾中的所有檔案包括子目錄 File[] files = dirFile.listFiles(); for (int i = 0; i < files.length; i++) { // 刪除子檔案 if (files[i].isFile()) { flag = ZipUtil.deleteFile(files[i].getAbsolutePath()); if (!flag) break; } // 刪除子目錄 else if (files[i].isDirectory()) { flag = ZipUtil.deleteDirectory(files[i].getAbsolutePath()); if (!flag) break; } } if (!flag) { System.out.println("刪除目錄失敗!"); return false; } // 刪除當前目錄 if (dirFile.delete()) { System.out.println("刪除目錄" + dir + "成功!"); return true; } else { return false; } } //判斷是否包含中文 private static boolean existZH(String str) { String regEx = "[\\u4e00-\\u9fa5]"; Pattern p = Pattern.compile(regEx); Matcher m = p.matcher(str); while (m.find()) { return true; } return false; } //生成隨機檔名,與檔案上傳命名一致 public static String getNowTime() { Calendar cal = Calendar.getInstance(); int year = cal.get(1); int month = cal.get(2) + 1; int day = cal.get(5); int hour = cal.get(10); int minute = cal.get(12); int second = cal.get(13); int mi = cal.get(14); long num = cal.getTimeInMillis(); int rand = (int) (Math.random() * 899999 + 100000); return (new StringBuilder()).append(year).append(month).append(day).append(hour).append(minute).append(second) .append(mi).append(num).append("_").append(rand).toString(); } /* sFile:原檔案地址,tFile目標檔案地址 */ public static void copyFile(String sFile, String tFile) { // System.out.println("原檔案地址"+sFile+"目標"+tFile); FileInputStream fi = null; FileOutputStream fo = null; FileChannel in = null; FileChannel out = null; File s = new File(sFile); File t = new File(tFile); if (s.exists() && s.isFile()) { // System.out.println("是檔案"); try { fi = new FileInputStream(s); fo = new FileOutputStream(t); in = fi.getChannel();// 得到對應的檔案通道 out = fo.getChannel();// 得到對應的檔案通道 in.transferTo(0, in.size(), out);// 連線兩個通道,並且從in通道讀取,然後寫入out通道 } catch (IOException e) { e.printStackTrace(); } finally { try { fi.close(); in.close(); fo.close(); out.close(); } catch (IOException e) { e.printStackTrace(); } } } } public static void copyFile2(String sFile, String tFile) { File srcFile = new File(sFile); if(srcFile.exists()){ File destFile = new File(tFile); try { FileUtils.copyFile(srcFile, destFile); } catch (IOException e) { e.printStackTrace(); } } } }