【问题标题】:Using java to extract .rar files使用java提取.rar文件
【发布时间】:2012-07-23 17:52:34
【问题描述】:

我正在寻找一种使用 Java 解压缩 .rar 文件的方法,并且无论我在哪里搜索,我都会一直使用相同的工具 - JavaUnRar。我一直在研究用这个解压缩 .rar 文件,但我似乎找到的所有方法都非常漫长和尴尬,就像在 this example 中一样。

我目前能够在 20 行或更少的代码中提取 .tar.tar.gz.zip.jar 文件,因此必须有一种更简单的方法来提取 .rar 文件,有人知道吗?

如果它可以帮助任何人,这是我用来提取 .zip.jar 文件的代码,它适用于两者

 public void getZipFiles(String zipFile, String destFolder) throws IOException {
    BufferedOutputStream dest = null;
    ZipInputStream zis = new ZipInputStream(
                                       new BufferedInputStream(
                                             new FileInputStream(zipFile)));
    ZipEntry entry;
    while (( entry = zis.getNextEntry() ) != null) {
        System.out.println( "Extracting: " + entry.getName() );
        int count;
        byte data[] = new byte[BUFFER];

        if (entry.isDirectory()) {
            new File( destFolder + "/" + entry.getName() ).mkdirs();
            continue;
        } else {
            int di = entry.getName().lastIndexOf( '/' );
            if (di != -1) {
                new File( destFolder + "/" + entry.getName()
                                             .substring( 0, di ) ).mkdirs();
            }
        }
        FileOutputStream fos = new FileOutputStream( destFolder + "/"
                                                     + entry.getName() );
        dest = new BufferedOutputStream( fos );
        while (( count = zis.read( data ) ) != -1) 
            dest.write( data, 0, count );
        dest.flush();
        dest.close();
    }
}

【问题讨论】:

  • 通过各种压缩文件,我假设您在 linux 环境中。为什么不从 Java 调用 shell 命令。它将更加分拣和更快。
  • 不,我实际上正在使用 Windows,但我目前正在处理的应用程序具有能够解压缩 .tar.gz 文件的规范,所以我必须这样做......我希望它是一个独立的应用程序,所以如果我能提供帮助,我真的不想在应用程序之外进行调用

标签: java extract rar


【解决方案1】:

您可以提取 .gz.zip.jar 文件,因为它们使用 Java SDK 中内置的多种压缩算法。

RAR 格式的情况有点不同。 RAR 是一种专有存档文件格式。 RAR license 不允许将其包含在 Java SDK 等软件开发工具中。

unrar文件的最佳方式是使用 3rd 方库,例如 junrar

您可以在 SO 问题 RAR archives with java 中找到对其他 Java RAR 库的一些引用。 SO问题How to compress text file to rar format using java program也解释了更多不同的解决方法(例如使用Runtime)。

【讨论】:

  • 我刚刚设置了 junrar,它在 mac 上运行良好。它需要 Apache Commons、Apache Commons VFS 和 log4j。
  • 但是如果它是一种专有格式,VFS 是如何使用它的呢?我还没有在它的代码中找到Runtime 方法。
【解决方案2】:

您可以简单地将这个 maven 依赖项添加到您的代码中:

<dependency>
    <groupId>com.github.junrar</groupId>
    <artifactId>junrar</artifactId>
    <version>0.7</version>
</dependency>

然后使用此代码提取 rar 文件:

        File rar = new File("path_to_rar_file.rar");
    File tmpDir = File.createTempFile("bip.",".unrar");
    if(!(tmpDir.delete())){
        throw new IOException("Could not delete temp file: " + tmpDir.getAbsolutePath());
    }
    if(!(tmpDir.mkdir())){
        throw new IOException("Could not create temp directory: " + tmpDir.getAbsolutePath());
    }
    System.out.println("tmpDir="+tmpDir.getAbsolutePath());
    ExtractArchive extractArchive = new ExtractArchive();
    extractArchive.extractArchive(rar, tmpDir);
    System.out.println("finished.");

【讨论】:

    【解决方案3】:

    您可以使用库junrar

    <dependency>
       <groupId>com.github.junrar</groupId>
       <artifactId>junrar</artifactId>
       <version>0.7</version>
    </dependency>
    

    代码示例:

                File f = new File(filename);
                Archive archive = new Archive(f);
                archive.getMainHeader().print();
                FileHeader fh = archive.nextFileHeader();
                while(fh!=null){        
                        File fileEntry = new File(fh.getFileNameString().trim());
                        System.out.println(fileEntry.getAbsolutePath());
                        FileOutputStream os = new FileOutputStream(fileEntry);
                        archive.extractFile(fh, os);
                        os.close();
                        fh=archive.nextFileHeader();
                }
    

    【讨论】:

    • 注意,junrar 不支持 RAR v5
    【解决方案4】:

    您可以使用http://sevenzipjbind.sourceforge.net/index.html

    除了支持大量存档格式外,16.02-2.01 版本还完全支持 RAR5 提取:

    • 密码保护档案
    • 带有加密标头的存档
    • 档案分卷

    分级

    implementation 'net.sf.sevenzipjbinding:sevenzipjbinding:16.02-2.01'
    implementation 'net.sf.sevenzipjbinding:sevenzipjbinding-all-platforms:16.02-2.01'
    

    或行家

    <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>
    

    以及代码示例

    
    import net.sf.sevenzipjbinding.ExtractOperationResult;
    import net.sf.sevenzipjbinding.IInArchive;
    import net.sf.sevenzipjbinding.SevenZip;
    import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
    import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem;
    
    import java.io.*;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * Responsible for unpacking archives with the RAR extension.
     * Support Rar4, Rar4 with password, Rar5, Rar5 with password.
     * Determines the type of archive itself.
     */
    public class RarExtractor {
    
        /**
         * Extracts files from archive. Archive can be encrypted with password
         *
         * @param filePath path to .rar file
         * @param password string password for archive
         * @return map of extracted file with file name
         * @throws IOException
         */
        public Map<InputStream, String> extract(String filePath, String password) throws IOException {
            Map<InputStream, String> extractedMap = new HashMap<>();
    
            RandomAccessFile randomAccessFile = new RandomAccessFile(filePath, "r");
            RandomAccessFileInStream randomAccessFileStream = new RandomAccessFileInStream(randomAccessFile);
            IInArchive inArchive = SevenZip.openInArchive(null, randomAccessFileStream);
    
            for (ISimpleInArchiveItem item : inArchive.getSimpleInterface().getArchiveItems()) {
                if (!item.isFolder()) {
                    ExtractOperationResult result = item.extractSlow(data -> {
                        extractedMap.put(new BufferedInputStream(new ByteArrayInputStream(data)), item.getPath());
    
                        return data.length;
                    }, password);
    
                    if (result != ExtractOperationResult.OK) {
                        throw new RuntimeException(
                                String.format("Error extracting archive. Extracting error: %s", result));
                    }
                }
            }
    
            return extractedMap;
        }
    }
    

    附: @BorisBrodski https://github.com/borisbrodski 祝你 40 岁生日快乐!希望你有一个伟大的庆祝活动。感谢您的工作!

    【讨论】:

      猜你喜欢
      • 2018-11-02
      • 1970-01-01
      • 1970-01-01
      • 2018-11-12
      • 1970-01-01
      • 2015-05-23
      • 2012-12-10
      • 2011-02-11
      • 2015-10-01
      相关资源
      最近更新 更多