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();
    }
}
M. A. Kishawy
  • 5,001
  • 11
  • 47
  • 72
flexinIT
  • 431
  • 2
  • 10
  • 28
  • 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. – Subir Kumar Sao Jul 25 '12 at 10:10
  • 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 it – flexinIT Jul 25 '12 at 10:14

5 Answers5

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

Community
  • 1
  • 1
Tom
  • 26,212
  • 21
  • 100
  • 111
  • 1
    I just set up junrar and it worked great in a mac. It requires Apache Commons, Apache Commons VFS and log4j. – dev4life Sep 10 '15 at 17:37
  • But if it's a proprietary format, how is VFS working with it? I haven't found a `Runtime` methods in its code. – Acuna Jul 23 '18 at 02:56
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();
}
Miss Chanandler Bong
  • 4,081
  • 10
  • 26
  • 36
Jeremias Santos
  • 377
  • 3
  • 5
2

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!

Alexey Bril
  • 479
  • 4
  • 14
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.");
adramazany
  • 625
  • 9
  • 15
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;

}
Alex A
  • 33
  • 5