Java解壓rar5相容rar4

O_O似曾相识發表於2024-07-30

  RAR檔案格式由WinRAR開發,廣泛用於檔案壓縮和歸檔。隨著技術的發展,RAR5作為更新的版本,引入了多項改進以提高壓縮效率和資料安全性。

  •   壓縮效率:RAR5透過增大字典大小至32MB,相較於RAR4的4MB,能夠更有效地找到資料中的重複模式,從而提高壓縮率,特別是在處理大型檔案時。
  •   安全性增強:RAR5採用的256位AES加密演算法,提供了更高階別的資料保護,相較於RAR4的加密標準,更難被破解。
  •   時間戳的國際化:RAR5使用UTC時間,解決了RAR4使用本地時間可能導致的時區混淆問題,使得檔案的時間戳在全球範圍內保持一致性。
  •   相容性考慮:RAR5的格式較新,可能不被舊版本的解壓軟體識別。在需要確保最大相容性的場景下,可能仍需使用RAR4格式。
  •   恢復卷的改進:RAR5格式支援的恢復卷數量大大增加,從RAR4的255個增加到65535個,這在處理多卷壓縮檔案時提供了更高的靈活性和容錯性。
  •   錯誤糾正能力:RAR5的恢復記錄基於Reed-Solomon錯誤糾正碼,顯著提高了壓縮檔案在受損情況下的自我修復能力。
  •   日誌檔案編碼:RAR5使用UTF-16小端位元組序編碼,確保了日誌檔案中Unicode字元的正確儲存和顯示,提高了對國際化檔名的支援。

RAR5的Java解壓實現

在Java中實現RAR5檔案的解壓,可以藉助java-unrarSevenZipJBinding庫。以下是具體的實現步驟和程式碼示例。

1、新增依賴:在專案的pom.xml檔案中新增相關依賴。

 <dependency>
            <groupId>com.github.axet</groupId>
            <artifactId>java-unrar</artifactId>
            <version>1.7.0-8</version>
        </dependency>
        <dependency>
            <groupId>net.sf.sevenzipjbinding</groupId>
            <artifactId>sevenzipjbinding</artifactId>
            <version>16.02-2.01</version>
        </dependency>
        <dependency>
            <groupId>net.sf.sevenzipjbinding</groupId>
            <artifactId>sevenzipjbinding-all-platforms</artifactId>
            <version>16.02-2.01</version>
        </dependency>

2、編寫解壓工具類:建立Rar5DocExtractor類,實現解壓邏輯。

  1 package rar5;
  2 
  3 import net.sf.sevenzipjbinding.*;
  4 import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
  5 
  6 import java.io.*;
  7 import java.util.*;
  8 
  9 public class Rar5DocExtractor {
 10 
 11     public List<File> extractFiles(File rarFile, File outputDir) throws IOException {
 12         Set<File> extractedFiles = new HashSet<>();
 13         if (!outputDir.exists()) {
 14             outputDir.mkdirs(); // 確保輸出目錄存在
 15         }
 16 
 17         RandomAccessFile randomAccessFile = null;
 18         IInArchive inArchive = null;
 19         try {
 20             randomAccessFile = new RandomAccessFile(rarFile, "r");
 21             inArchive = SevenZip.openInArchive(null, new RandomAccessFileInStream(randomAccessFile));
 22             int[] in = new int[inArchive.getNumberOfItems()];
 23             for (int i = 0; i < in.length; i++) {
 24                 in[i] = i;
 25             }
 26             inArchive.extract(in, false, new ExtractCallback(inArchive, outputDir.getAbsolutePath(), extractedFiles));
 27         } finally {
 28             if (randomAccessFile != null) {
 29                 randomAccessFile.close();
 30             }
 31             if (inArchive != null) {
 32                 try {
 33                     inArchive.close();
 34                 } catch (SevenZipException e) {
 35                     e.printStackTrace();
 36                 }
 37             }
 38         }
 39         List<File> list=new ArrayList<>(extractedFiles);
 40         return list;
 41     }
 42 
 43     private static class ExtractCallback implements IArchiveExtractCallback {
 44         private IInArchive inArchive;
 45         private String outDir;
 46         private Set<File> extractedFiles;
 47         // 用於跟蹤是否需要關閉流的變數
 48         private OutputStream fos = null;
 49         private boolean closeStreamAfterOperation = false; // 標記流是否需要關閉
 50 
 51         public ExtractCallback(IInArchive inArchive, String outDir, Set<File> extractedFiles) {
 52             this.inArchive = inArchive;
 53             this.outDir = outDir;
 54             this.extractedFiles = extractedFiles;
 55         }
 56 
 57         @Override
 58         public void setCompleted(long arg0) throws SevenZipException {
 59         }
 60 
 61         @Override
 62         public void setTotal(long arg0) throws SevenZipException {
 63         }
 64 
 65 
 66         @Override
 67         public ISequentialOutStream getStream(int index, ExtractAskMode extractAskMode) throws SevenZipException {
 68             final String path = (String) inArchive.getProperty(index, PropID.PATH);
 69             // 這裡不再建立 File 物件,避免多次呼叫 getStream 時重複建立
 70             return new ISequentialOutStream() {
 71                 public int write(byte[] data) throws SevenZipException {
 72                     File file = new File(outDir, path);
 73                     try {
 74                         if (data.length == 0) return 0;
 75                         file.getParentFile().mkdirs(); // 確保目錄存在
 76                         if (fos == null) { // 如果這是第一次寫入,初始化輸出流
 77                             fos = new FileOutputStream(file);
 78                             closeStreamAfterOperation = true; // 設定標記,表示需要在操作結果後關閉流
 79                         }
 80                         fos.write(data);
 81                         fos.flush(); // 重新整理以確保資料被寫入磁碟
 82                         extractedFiles.add(file); // 新增到提取檔案集合
 83                     } catch (IOException e) {
 84                         throw new SevenZipException("Error writing data to file: " + path, e);
 85                     }
 86                     return data.length;
 87                 }
 88             };
 89         }
 90 
 91         @Override
 92         public void prepareOperation(ExtractAskMode arg0) throws SevenZipException {
 93         }
 94 
 95         @Override
 96         public void setOperationResult(ExtractOperationResult extractOperationResult) throws SevenZipException {
 97             if (closeStreamAfterOperation && fos != null) {
 98                 try {
 99                     // 關閉輸出流
100                     fos.close();
101                 } catch (IOException e) {
102                     throw new SevenZipException("關閉檔案輸出流時報錯", e);
103                 } finally {
104                     // 重置標記
105                     closeStreamAfterOperation = false;
106                     // 清除引用,以便垃圾回收
107                     fos = null;
108                 }
109             }
110         }
111 
112     }
113 }

3、編寫測試類:建立測試類以驗證RAR5檔案的解壓功能。

 1 package rar5;
 2 
 3 import java.io.File;
 4 import java.io.IOException;
 5 import java.util.List;
 6 
 7 public class RAR5ExtractorTest {
 8 
 9     public static void main(String[] args) {
10         File rarDirFile = new File("src/main/resources/rar5Test06.rarbak");
11         File outDirFile = new File("src/main/resources/temp/rar5Test06.rar");
12 
13         Rar5DocExtractor extractor = new Rar5DocExtractor();
14         try {
15             List<File> extractedFiles = extractor.extractFiles(rarDirFile, outDirFile);
16             System.out.println("Extracted files:");
17             for (File file : extractedFiles) {
18                 System.out.println(file.getAbsolutePath());
19             }
20         } catch (IOException e) {
21             e.printStackTrace();
22         }
23     }
24 }

相關文章