libarchive-c Python Interface
libarchive-c is a Python interface to the C library libarchive, allowing users to read, write, and extract various archive formats like tar, zip, and 7z. It leverages `ctypes` for dynamic loading and is actively maintained, with regular releases (e.g., v5.3 released May 22, 2025). It is currently tested with Python 3.12 and 3.13.
Common errors
-
OSError: [WinError 126] The specified module could not be found Traceback (most recent call last): File "<stdin>", line 1, in <module> File "...\libarchive\__init__.py", line 45, in <module> libarchive = ctypes.cdll.LoadLibrary(libarchive_path) File "C:\Python3x\lib\ctypes\__init__.py", line xxx, in LoadLibrary return self._dlltype(name)cause The native `libarchive` C library (e.g., `archive.dll` on Windows) or one of its dependencies cannot be found by Python's `ctypes`.fix1. Install the `libarchive` C library for your system. 2. For Windows, ensure `libarchive.dll` and its dependencies (like `libcrypto-1_1-x64.dll`, `VCRUNTIME140.dll`) are either in your system PATH or in the same directory as your Python script, or explicitly set the `LIBARCHIVE` environment variable to the full path of `libarchive.dll` before running your Python script. -
ImportError: cannot import name 'ArchiveRead' from 'libarchive' (<path_to_site-packages>/libarchive/__init__.py)
cause The high-level API of `libarchive-c` primarily exposes functions like `file_reader`, `file_writer`, and `extract_file` directly under the `libarchive` module. The `ArchiveRead` and `ArchiveWrite` classes are part of the lower-level FFI or internal implementation and not directly exposed for top-level import in the current recommended API.fixUse the recommended high-level functions. Instead of `from libarchive import ArchiveRead`, use `import libarchive` and then `with libarchive.file_reader(...) as archive:` to get an archive object. `ArchiveEntry` objects are yielded by iterating the archive object.
Warnings
- breaking If you use the `archive_read_class` or `archive_write_class` arguments for custom archive handling, the classes you provide will now receive a `codec` name as a second positional argument.
- breaking Archive extraction functions now pass `SECURE_NODOTDOT`, `SECURE_NOABSOLUTEPATHS`, and `SECURE_SYMLINKS` flags by default, unless extracting to the root directory. This enhances security but might alter behavior for paths containing '..' or absolute paths within archives, or symbolic links.
- breaking The `ArchiveEntry` properties `atime`, `mtime`, `ctime`, `birthtime`, and `size` now return `None` instead of `0` when the corresponding metadata is unset in the archive.
- breaking The `ArchiveEntry.pathname` property now attempts to decode bytes using UTF-8 by default, which may break reading archives containing non-UTF-8 filenames that coincidentally resemble UTF-8.
- breaking Support for Python 2.7 has been dropped.
- gotcha The `libarchive-c` Python package is a wrapper around the native `libarchive` C library. This C library must be installed on your system for `libarchive-c` to function.
- gotcha Older or obsolete versions of the `libarchive` C library (especially those bundled with some operating systems like macOS) may not work correctly or support all features. Python `libarchive-c` is tested against newer versions.
Install
-
pip install libarchive-c
Imports
- extract_file
import libarchive libarchive.extract_file(...)
- file_reader
import libarchive with libarchive.file_reader(...) as archive:
- file_writer
import libarchive with libarchive.file_writer(...) as archive:
- ArchiveEntry
from libarchive import ArchiveEntry
import libarchive entry = libarchive.ArchiveEntry(...)
Quickstart
import libarchive
import os
# Create a dummy file
with open('test_file.txt', 'w') as f:
f.write('Hello, libarchive-c!')
# Create an archive
archive_name = 'my_archive.tar'
with libarchive.file_writer(archive_name, 'tar') as archive:
archive.add_files('test_file.txt')
print(f"Archive '{archive_name}' created.")
# Clean up the dummy file
os.remove('test_file.txt')
# Read and extract the archive
extracted_dir = 'extracted_content'
os.makedirs(extracted_dir, exist_ok=True)
os.chdir(extracted_dir)
libarchive.extract_file(os.path.join('..', archive_name)) # Extract from parent dir
os.chdir('..')
# Verify extraction
extracted_path = os.path.join(extracted_dir, 'test_file.txt')
if os.path.exists(extracted_path):
with open(extracted_path, 'r') as f:
content = f.read()
print(f"Content extracted: {content}")
else:
print("Extraction failed.")
# Clean up archive and extracted directory
os.remove(archive_name)
os.remove(extracted_path)
os.rmdir(extracted_dir)