7z

7z is the archive format of the 7-Zip utility. Compress4J creates 7z archives and extracts them, including password-protected ones.

Extraction goes through the same guards as every other format: path traversal is rejected, and escapingSymlinkPolicy and the limits (limits(…​), maxEntries, maxEntrySize, maxTotalSize, maxRatio) apply. See Security.

Example Usage

7z Creation
try (SevenZArchiveCreator sevenZCreator =
        SevenZArchiveCreator.builder(Path.of("example.7z")).build()) {
    sevenZCreator.addFile(Path.of("path/to/file.txt"));
    sevenZCreator.addDirectoryRecursively(Path.of("sourceDir"));
}
7z Extraction
try (SevenZArchiveExtractor sevenZExtractor = SevenZArchiveExtractor.builder(Path.of("example.7z"))
        .overwrite(true)
        .stripComponents(1)
        .filter(entry -> entry.name().endsWith(".txt"))
        .errorHandler((entry, exception) -> SKIP)
        .escapingSymlinkPolicy(EscapingSymlinkPolicy.DISALLOW)
        .build()) {
    sevenZExtractor.extract(Path.of("outputDir"));
}
Extracting a password-protected archive
try (SevenZArchiveExtractor sevenZExtractor = SevenZArchiveExtractor.builder(Path.of("encrypted.7z"))
        .password("secret".toCharArray())
        .maxEntries(10_000)
        .maxTotalSize(1024L * 1024 * 1024)
        .build()) {
    sevenZExtractor.extract(Path.of("outputDir"));
}

Notes

  • The creator writes to a file path or a SeekableByteChannel, because 7z must seek back to patch its header. A channel is written from offset 0.

  • The creator does not encrypt. Only extraction accepts a password.

  • A symbolic link is stored the way p7zip stores it, as a Unix-mode entry whose content is the link target, and is restored as a symlink on extraction.

  • A wrong or missing password fails with an IOException.

7z extraction when you hold an InputStream
long maxArchiveSize = 512L * 1024 * 1024;
Files.createDirectories(outputDir);
Path spool = Files.createTempFile(
        outputDir.toAbsolutePath().getParent(),
        "archive",
        ".7z"); // 7z needs random access, so spool the stream to disk
try {
    try (OutputStream out = Files.newOutputStream(spool)) {
        byte[] buffer = new byte[8192];
        long copied = 0;
        for (int read; (read = download.read(buffer)) != -1; ) {
            copied += read;
            if (copied > maxArchiveSize) {
                throw new IOException("Archive exceeds " + maxArchiveSize + " bytes");
            }
            out.write(buffer, 0, read);
        }
    }
    try (var extractor = SevenZArchiveExtractor.builder(spool)
            .maxEntries(10_000)
            .maxEntrySize(100L * 1024 * 1024)
            .maxTotalSize(1024L * 1024 * 1024)
            .build()) {
        extractor.extract(outputDir);
    }
} finally {
    Files.deleteIfExists(spool);
}
7z keeps its header at the end of the archive, so it reads only from a file or a SeekableByteChannel. The example spools the stream to a temp file outside the output directory, stops the copy at a size cap, and applies extraction limits to the result. Choose both bounds for your input.