Using java to extract .rar files
Asked Answered
A

6

19

I am looking a ways to unzip .rar files using Java and where ever I search i keep ending up with the same tool - JavaUnRar. I have been looking into unzipping .rar files with this but all the ways i seem to find to do this are very long and awkward like in this example

I am currently able to extract .tar, .tar.gz, .zip and .jar files in 20 lines of code or less so there must be a simpler way to extract .rar files, does anybody know?

Just if it helps anybody this is the code that I am using to extract both .zip and .jar files, it works for both

 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();
    }
}
Amberly answered 25/7, 2012 at 10:6 Comment(2)
By the variety of zipping files I assume you are in linux env. Why don't you call shell commands from Java. It will be sorter and faster.Zaragoza
No i am actually using windows but the application i am working on at the moment has specifications to be able to unzip .tar.gz files so I have to do it... I want it to be a stand alone application so I don't really want to be doing calls outside of the application if i can help itAmberly
C
21

You are able to extract .gz, .zip, .jar files as they use number of compression algorithms built into the Java SDK.

The case with RAR format is a bit different. RAR is a proprietary archive file format. RAR license does not allow to include it into software development tools like Java SDK.

The best way to unrar your files will be using 3rd party libraries such as junrar.

You can find some references to other Java RAR libraries in SO question RAR archives with java. Also SO question How to compress text file to rar format using java program explains more on different workarounds (e.g. using Runtime).

Childbearing answered 12/1, 2013 at 1:33 Comment(2)
I just set up junrar and it worked great in a mac. It requires Apache Commons, Apache Commons VFS and log4j.Sepulture
But if it's a proprietary format, how is VFS working with it? I haven't found a Runtime methods in its code.Xenophanes
F
5

You can use http://sevenzipjbind.sourceforge.net/index.html

In addition to supporting a large number of archive formats, version 16.02-2.01 has full support for RAR5 extraction with:

  • password protected archives
  • archives with encrypted headers
  • archives splitted in volumes

gradle

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

or maven

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

And code example


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

P.S. @BorisBrodski https://github.com/borisbrodski Happy 40th birthday to you! Hope you had a great celebration. Thanks for your work!

Fleawort answered 17/12, 2020 at 10:58 Comment(0)
T
2

You can use the library junrar

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

Code example:

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();
}
Toothpick answered 19/3, 2019 at 20:55 Comment(1)
Beware, junrar does not support RAR v5Kealey
F
1

you could simply add this maven dependency to you code:

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

and then use this code for extract rar file:

        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.");
Flowerpot answered 19/4, 2018 at 6:21 Comment(0)
L
0

This method helps to extract files to streams from rar(RAR5) file stream if you have input stream. In my case I was processing MimeBodyPart from email.

The example from @Alexey Bril didn't work for me.

Dependencies are the same

Gradle

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

Maven

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

Code

private List<InputStream> getInputStreamsFromRar5InputStream(InputStream is) throws IOException {

    List<InputStream> inputStreams = new ArrayList<>();
    
    File tempFile = File.createTempFile("tempRarArchive-", ".rar", null);

    try (FileOutputStream fos = new FileOutputStream(tempFile)) {
        fos.write(is.readAllBytes());
        fos.flush();
        try (RandomAccessFile raf = new RandomAccessFile(tempFile, "r")) {// open for reading
            try (IInArchive inArchive = SevenZip.openInArchive(null, // autodetect archive type
                    new RandomAccessFileInStream(raf))) {
                // Getting simple interface of the archive inArchive
                ISimpleInArchive simpleInArchive = inArchive.getSimpleInterface();

                for (ISimpleInArchiveItem item : simpleInArchive.getArchiveItems()) {
                    if (!item.isFolder()) {
                        ExtractOperationResult result;
                        final InputStream[] IS = new InputStream[1];

                        final Integer[] sizeArray = new Integer[1];
                        result = item.extractSlow(new ISequentialOutStream() {
                            /**
                             * @param bytes of extracted data
                             * @return size of extracted data
                             */
                            @Override
                            public int write(byte[] bytes) {
                                InputStream is = new ByteArrayInputStream(bytes);
                                sizeArray[0] = bytes.length;
                                IS[0] = new BufferedInputStream(is); // Data to write to file
                                return sizeArray[0];
                            }
                        });

                        if (result == ExtractOperationResult.OK) {
                            inputStreams.add(IS[0]);
                        } else {
                            log.error("Error extracting item: " + result);
                        }
                    }
                }
            }
        }
        
    } finally {
        tempFile.delete();
    }

    return inputStreams;

}
Luxury answered 27/10, 2022 at 14:24 Comment(0)
P
0

There is a commercial Java library - Aspose.ZIP for Java that knows how to open many different archive formats, including RAR:

try (RarArchive archive = new RarArchive("input_archive.rar")) 
{
   archive.extractToDirectory("\\outputDirectory");
}

Installation:

<repositories>
   <repository>
       <id>AsposeJavaAPI</id>
       <name>Aspose Java API</name>
       <url>https://releases.aspose.com/java/repo/</url>
   </repository>
</repositories>

<dependency>
   <groupId>com.aspose</groupId>
   <artifactId>aspose-zip</artifactId>
   <version>24.3</version>
</dependency>

More info: https://docs.aspose.com/zip/java/how-to/#java-extract-rar-file

Potful answered 25/4 at 12:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.