Java解压rar5兼容rar4
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-unrar
和SevenZipJBinding
库。以下是具体的实现步骤和代码示例。
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 }