PyEasyArchive
A very intuitive and useful adapter to libarchive for universal archive access.
A ctypes-based adapter to libarchive. The source-code is written to be clear and intuitive. The project is written primarily in Python, distributed under the MIT License license, first published in 2014. Key topics include: 7z, 7zip, archive, bzip2, gz.
Introduction
A ctypes-based adapter to libarchive. The source-code is written to be clear
and intuitive.
Even 7-Zip is supported for both reading and writing.
I could definitely use some help, if any is available. Completeness will
require a bit more work (see libarchive's archive.h and archive_entry.h).
Installation
PyPI:
$ pip install libarchive
Notes
- The Ubuntu
libarchivepackage maintainer only provides a "libarchive.so" symlink in the dev package so you'll have to install thelibarchive-devpackage.
$ apt-get install libarchive-dev
-
Encryption is not currently supported since it's not supported in the underlying library (libarchive). Note this inquiry and the wishlist item.
-
OS X has a system version of
libarchivethat is very old. As a result, many users have encountered issues importing an alternate one. Specifically, often they install a different one via Brew but this will not be [sym]linked into the system like other packages. This is a precaution taken by Brew to prevent undefined behavior in the parts of OS X that depend on the factory version. In order to work around this, you should setLD_LIBRARY_PATH(or prepend ifLD_LIBRARY_PATHis already defined) with the path of the location of the library version you want to use. You'll want to set this from your user-profile script (unless your environment can not support this and you need to prepend something like "LD_LIBRARY_PATH=/some/path" to the front of the command-line or set it viaos.environabove where you import this package). A tool has been provided that will print the path of the first version oflibarchiveinstalled via Brew. Just copy-and-paste it. Thanks to @SkyLeach for discussing the issue and treatments.
Examples
To extract to the current directory from a physical file (and print each
relative filepath):
pythonimport libarchive.public for entry in libarchive.public.file_pour('/tmp/test.zip'): print(entry)
To extract to the current directory from memory:
pythonimport libarchive.public with open('/tmp/test.zip', 'rb') as f: for entry in libarchive.public.memory_pour(f.read()): print(entry)
To read files from a physical archive:
pythonimport libarchive.public with libarchive.public.file_reader('test.7z') as e: for entry in e: with open('/tmp/' + str(entry), 'wb') as f: for block in entry.get_blocks(): f.write(block)
To read files from memory:
pythonimport libarchive.public with open('test.7z', 'rb') as f: buffer_ = f.read() with libarchive.public.memory_reader(buffer_) as e: for entry in e: with open('/tmp/' + str(entry), 'wb') as f: for block in entry.get_blocks(): f.write(block)
To specify a format and/or filter for reads (rather than detecting it):
pythonimport libarchive.public import libarchive.constants with open('test.7z', 'rb') as f: buffer_ = f.read() with libarchive.public.memory_reader( buffer_, format_code=libarchive.constants.ARCHIVE_FORMAT_TAR_USTAR, filter_code=libarchive.constants.ARCHIVE_FILTER_GZIP ) as e: for entry in e: with open('/tmp/' + str(entry), 'wb') as f: for block in entry.get_blocks(): f.write(block)
To read the "filetype" flag for each entry:
pythonimport libarchive.public with open('test.7z', 'rb') as f: buffer_ = f.read() with libarchive.public.memory_reader(f.read()) as e: for entry in e: print(entry.filetype)
The output of this is:
pythonEntryFileType(IFREG=True, IFLNK=True, IFSOCK=True, IFCHR=False, IFBLK=False, IFDIR=False, IFIFO=False) EntryFileType(IFREG=True, IFLNK=True, IFSOCK=True, IFCHR=False, IFBLK=False, IFDIR=False, IFIFO=False) EntryFileType(IFREG=True, IFLNK=True, IFSOCK=True, IFCHR=False, IFBLK=False, IFDIR=False, IFIFO=False)
To create a physical archive from physical files:
pythonimport libarchive.public import libarchive.constants libarchive.public.create_file( 'create.7z', libarchive.constants.ARCHIVE_FORMAT_7ZIP, ['/etc/profile']):
The path of the file to add will be recorded verbatim.
To create an archive in memory from physical files:
pythonimport libarchive.public import libarchive.constants with open('/tmp/new.7z', 'wb') as f: def writer(buffer_, length): f.write(buffer_) return length libarchive.public.create_generic( writer, format_name=libarchive.constants.ARCHIVE_FORMAT_7ZIP, files=['/etc/profile']):
Testing
libarchive uses nose/nose2 for testing:
tests$ ./run.py
Contributors
Showing top 6 contributors by commit count.
