Fading Coder

One Final Commit for the Last Sprint

Home > Tools > Content

Extracting RAR Archives in Java with the Junrar Library

Tools 1

Integrating the junrar dependency into a build configuration establishes the necessary parsing capabilities for RAR archives. The following Maven declaration resolves the required binaries.

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

Once the library is available, the extraction routine requires initializing an archive reader, traversing the internal header table, and routing decompressed payloads to designated file paths. The implementation below leverages modern Java I/O practices and automatic resource management to handle directory creation and stream allocation safely.

import com.github.junrar.Archive;
import com.github.junrar.rarfile.FileHeader;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class RarExtractor {

    public static void decompress(Path sourceArchive, Path destinationRoot) throws IOException {
        Files.createDirectories(destinationRoot);

        try (Archive archiveReader = new Archive(sourceArchive.toFile())) {
            FileHeader currentEntry = archiveReader.nextFileHeader();

            while (currentEntry != null) {
                String sanitizedPath = currentEntry.getFileNameString().trim();
                Path targetLocation = destinationRoot.resolve(sanitizedPath);

                if (currentEntry.isDirectory()) {
                    Files.createDirectories(targetLocation);
                } else {
                    Files.createDirectories(targetLocation.getParent());
                    try (OutputStream writeStream = Files.newOutputStream(targetLocation)) {
                        archiveReader.extractFile(currentEntry, writeStream);
                    }
                }
                currentEntry = archiveReader.nextFileHeader();
            }
        } catch (Exception processingError) {
            throw new IOException("RAR extraction aborted due to invalid structure or I/O failure", processingError);
        }
    }

    public static void main(String[] runtimeArgs) {
        Path compressedInput = Paths.get("dataset_backup.rar");
        Path extractionBase = Paths.get("recovered_data");

        try {
            decompress(compressedInput, extractionBase);
        } catch (IOException operationFailure) {
            System.err.println("Extraction process terminated: " + operationFailure.getMessage());
        }
    }
}

The parsing mechanism operates by reading the archive's central directory sequentially. Each iteration evaluates metadata properties, resolves relative paths against the output root, and instantiates the appropriate file system entities. Directory headers trigger recursive path creation, while file headers initiate a byte-stream transfer. The extraction API handles decompression internally, writing the result directly to the provided output channel. When the header iterator returns a null reference, the archive pointer is automatically cleared by the try-with-resources boundary.

The interaction sequence between the client application, the library core, and the underlying file system follows this progression:

sequenceDiagram
    participant App as Extraction Client
    participant Core as Archive Parser
    participant FS as File System

    App->>Core: Instantiate with target archive
    loop Iterate Headers
        Core-->>App: Deliver next entry metadata
        alt Entry represents folder
            App->>FS: Generate directory tree
        else Entry represents data
            App->>FS: Validate parent path existence
            App->>Core: Open output channel
            Core->>FS: Flush decompressed stream
            FS-->>App: Acknowledge write operation
        end
    end
    App->>Core: Release archive lock

State management during execution transitions through three primary phases. The system begins in a standby configuration until the constructor validates the archive signature and allocates memory buffers. As the iteration advances, the parser shifts into a traversal state, continuously evaluating entry flags and updating the internal cursor. Upon encountering a data payload, the process enters an active I/O state where decompression algorithms run synchronously until the current file boundary is reached. Completion of the header sequence forces a transition to a termination state, ensuring all native handles are closed and resources are returned to the operating system.

Related Articles

Efficient Usage of HTTP Client in IntelliJ IDEA

IntelliJ IDEA incorporates a versatile HTTP client tool, enabling developres to interact with RESTful services and APIs effectively with in the editor. This functionality streamlines workflows, replac...

Installing CocoaPods on macOS Catalina (10.15) Using a User-Managed Ruby

System Ruby on macOS 10.15 frequently fails to build native gems required by CocoaPods (for example, ffi), leading to errors like: ERROR: Failed to build gem native extension checking for ffi.h... no...

Resolve PhpStorm "Interpreter is not specified or invalid" on WAMP (Windows)

Symptom PhpStorm displays: "Interpreter is not specified or invalid. Press ‘Fix’ to edit your project configuration." This occurs when the IDE cannot locate a valid PHP CLI executable or when the debu...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.