junrar
| Language | Java 8+ |
|---|---|
| License | UnRAR license: free, but not OSI open source; may not be used to develop a RAR-compatible archiver |
| Repository | github.com/junrar/junrar |
| Documentation | README, Javadoc |
| Depends on | SLF4J API |
| Read / write | yes / no; RAR4 and RAR5 (since 8.0), passwords and encrypted headers, multi-volume |
junrar is a Java port of the UnRAR code. It needs no native library, so it works the same on every platform the JVM runs on. Version 8 added RAR5 extraction; older versions (7.x and earlier) read only RAR4 and throw an exception on RAR5 files, so check which version your dependencies pull in.
The Junrar class has static helpers that extract a whole archive in one call. The Archive class gives access to each FileHeader and extracts entries to an OutputStream or InputStream. An Archive isn’t thread-safe.
Installation#
Maven:
<dependency>
<groupId>com.github.junrar</groupId>
<artifactId>junrar</artifactId>
<version>8.1.2</version>
</dependency>
Gradle:
implementation "com.github.junrar:junrar:8.1.2"
Basic usage: extract a RAR file#
import com.github.junrar.Junrar;
import com.github.junrar.exception.RarException;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class Extract {
public static void main(String[] args) {
try {
List<File> files = Junrar.extract("archive.rar", "output");
for (File f : files) {
System.out.println(f.getPath());
}
} catch (RarException | IOException e) {
System.err.println("extract failed: " + e.getMessage());
}
}
}
The destination folder must exist. Entries with paths that point outside the destination are rejected.
How to list the files in a RAR#
import com.github.junrar.Archive;
import com.github.junrar.rarfile.FileHeader;
import java.io.File;
try (Archive archive = new Archive(new File("archive.rar"))) {
// RarFormat.RAR50 for RAR5, RAR15 for RAR 1.5-4.x archives
System.out.println("format: " + archive.getFormat() + ", encrypted: " + archive.isEncrypted());
for (FileHeader fh : archive) {
System.out.printf("%s%s %d bytes %s%n",
fh.getFileName(), fh.isDirectory() ? "/" : "",
fh.getFullUnpackSize(), fh.getMTime());
}
}
Junrar.getContentsDescription(new File("archive.rar")) returns the same as a list of ContentDescription objects with path and size fields.
How to read a file from a RAR as a stream#
import com.github.junrar.Archive;
import com.github.junrar.rarfile.FileHeader;
import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
try (Archive archive = new Archive(new File("archive.rar"))) {
FileHeader fh;
while ((fh = archive.nextFileHeader()) != null) {
if (fh.isDirectory() || !fh.getFileName().endsWith(".txt")) continue;
try (InputStream in = archive.getInputStream(fh)) {
Files.copy(in, Paths.get("out", new File(fh.getFileName()).getName()),
StandardCopyOption.REPLACE_EXISTING);
}
}
}
archive.extractFile(fh, outputStream) writes an entry to any OutputStream. A CRC mismatch surfaces as an IOException from the stream (or a RarException from extractFile).
How to extract a password-protected RAR#
import com.github.junrar.Junrar;
import com.github.junrar.exception.WrongPasswordException;
try {
Junrar.extract("secret.rar", "output", "password");
} catch (WrongPasswordException e) {
System.err.println("wrong password");
}
With the Archive API, use new Archive(new File("secret.rar"), "password") or build options with a char[] password, which can be wiped from memory after use:
import com.github.junrar.ArchiveOptions;
char[] password = readPassword();
ArchiveOptions options = ArchiveOptions.builder().password(password).build();
try (Archive archive = new Archive(new File("secret.rar"), options)) {
// ...
}
archive.isPasswordProtected() tells whether a password is needed before you try to extract.
How to extract a multi-volume RAR#
Pass the first volume. junrar opens name.part2.rar, name.part3.rar (or .r00, .r01) from the same folder as needed:
Junrar.extract("movie.part1.rar", "output");
A missing volume throws MissingNextVolumeException. Volumes can only be followed when reading from a File; the InputStream constructors handle single-volume archives.
Tips#
- Catch
UnsupportedRarVersionExceptionfor archives from very old or future RAR versions. ArchiveOptions.builder().maxDictionarySize(...)limits memory for untrusted RAR 7.0 archives with huge dictionaries; the default limit is 4 GB.- In a solid archive, read entries in archive order with
nextFileHeader(): each entry depends on the ones before it.