All formats

libarchive-c

LanguagePython 3
LicenseCC0 (public domain dedication); libarchive itself is BSD 2-clause
Repositorygithub.com/Changaco/python-libarchive-c
DocumentationREADME
Depends onthe libarchive shared library (libarchive.so, libarchive.dylib, archive.dll)
Read / writeyes / yes; everything libarchive supports for 7z, including BCJ2; no encryption

libarchive-c loads the C libarchive library with ctypes and wraps its streaming API in Python context managers: file_reader to iterate over the entries of an archive, file_writer to create one, extract_file to unpack to disk. The same code reads 7z, TAR (all compressions), ZIP, ISO, CPIO, RAR and more; libarchive detects the format.

For 7z it reads LZMA, LZMA2, PPMd, BZip2, Deflate, Zstandard and the BCJ/BCJ2 filters, and writes LZMA2 (default), LZMA1, PPMd, BZip2, Deflate, Zstandard or stored archives. It can’t open encrypted 7z archives; use py7zr for those.

Installation#

Shell
pip install libarchive-c
# plus the C library:
sudo apt install libarchive13      # Debian / Ubuntu
brew install libarchive            # macOS

macOS ships an old libarchive without 7z write support; point the binding to Homebrew’s copy with the LIBARCHIVE environment variable, for example export LIBARCHIVE=$(brew --prefix libarchive)/lib/libarchive.dylib. On Windows install libarchive with vcpkg or conda and set LIBARCHIVE to the path of archive.dll.

Basic usage: list and extract a 7z archive#

Python
import os
import libarchive

# list entries and read their data
with libarchive.file_reader("archive.7z") as archive:
    for entry in archive:
        print(entry.pathname, entry.size, "dir" if entry.isdir else "")

# extract to a folder (extract_file writes into the current directory)
os.makedirs("output", exist_ok=True)
os.chdir("output")
libarchive.extract_file("../archive.7z")

By default extract_file uses the secure flags (no .., no absolute paths, no writing through symlinks).

How to read a file from a 7z archive into memory#

Entries must be read in order while iterating; their data is available only for the current entry:

Python
import libarchive

with libarchive.file_reader("archive.7z") as archive:
    for entry in archive:
        if entry.pathname == "docs/readme.txt":
            data = b"".join(entry.get_blocks())
            print(data.decode("utf-8"))
            break

How to create a 7z archive#

Python
import libarchive

with libarchive.file_writer("backup.7z", "7zip") as archive:
    archive.add_files("photos", "report.pdf")   # files and folders, recursively

    text = b"created by my app\n"
    archive.add_file_from_memory("notes/readme.txt", len(text), text)

Set compression with libarchive format options:

Python
with libarchive.file_writer("backup.7z", "7zip", options="compression=ppmd,compression-level=9") as archive:
    archive.add_files("logs")

Valid values for compression: copy, deflate, bzip2, lzma1, lzma2, ppmd, zstd (the last one needs a libarchive built with zstd).

How to open a 7z archive from bytes#

Python
import libarchive

with open("archive.7z", "rb") as f:
    buf = f.read()

with libarchive.memory_reader(buf) as archive:
    for entry in archive:
        print(entry.pathname)

Tips#