I am trying to selectively extract files from many 7zip files automatically, the usual patool
and pyunpack
and the like don’t allow selection of files to be extracted. py7zr
seems to provide the functionality however I find it extremely inefficient to extract individual files.
I found libarchive-c
after crafting this Google query manually:
https://www.google.com/search?q=%22python%22+%227z%22+-patool+-pyunpack+-py7zr&tbs=li:1
And sifting through the trash it still returns.
I installed this version of libarchive
, I downloaded the binary for Windows 10 x64 here.
I extracted the files from the libarchive package to D:Programslibarchive.
At first I can’t even import libarchive
:
In [20]: import libarchive
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Input In [20], in <cell line: 1>()
----> 1 import libarchive
File C:Program FilesPython310libsite-packageslibarchive__init__.py:1, in <module>
----> 1 from .entry import ArchiveEntry
2 from .exception import ArchiveError
3 from .extract import extract_fd, extract_file, extract_memory
File C:Program FilesPython310libsite-packageslibarchiveentry.py:6, in <module>
3 from enum import IntEnum
4 import math
----> 6 from . import ffi
9 class FileType(IntEnum):
10 NAMED_PIPE = AE_IFIFO = 0o010000 # noqa: E221
File C:Program FilesPython310libsite-packageslibarchiveffi.py:26, in <module>
23 page_size = mmap.PAGESIZE
25 libarchive_path = os.environ.get('LIBARCHIVE') or find_library('archive')
---> 26 libarchive = ctypes.cdll.LoadLibrary(libarchive_path)
29 # Constants
31 ARCHIVE_EOF = 1 # Found end of archive.
File C:Program FilesPython310libctypes__init__.py:452, in LibraryLoader.LoadLibrary(self, name)
451 def LoadLibrary(self, name):
--> 452 return self._dlltype(name)
File C:Program FilesPython310libctypes__init__.py:364, in CDLL.__init__(self, name, mode, handle, use_errno, use_last_error, winmode)
362 import nt
363 mode = nt._LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
--> 364 if '/' in name or '\' in name:
365 self._name = nt._getfullpathname(self._name)
366 mode |= nt._LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
TypeError: argument of type 'NoneType' is not iterable
It is extremely easy to figure out what is wrong, at least for me. It is because of this line:
libarchive_path = os.environ.get('LIBARCHIVE') or find_library('archive')
It searches for the environment variable to file the path of libarchive library, but I downloaded a .zip package not an installer which doesn’t set the environment variables, so the first command returns None
. Of course it means the second command also failed.
So I had to manually supply the correct path. It is not well-documented, at least I haven’t found it, but the line immediately below it is:
libarchive = ctypes.cdll.LoadLibrary(libarchive_path)
It means the path is expected to be a .dll path, so I changed it to this:
libarchive_path = "D:/Programs/libarchive/bin/archive.dll"
But I still can’t import libarchive
:
FileNotFoundError: Could not find module 'D:Programslibarchivebinarchive.dll' (or one of its dependencies). Try using the full path with constructor syntax.
I have searched this error and have found a lot of irrelevant information. I have found many posts similar to this: Can’t import dll module in Python
But they are all unhelpful, as I have supplied the absolute path while they are all dealing about relative path.
So the first part of the message is False
, that must not be the case, the file must have been indeed found, or there is a serious bug in the library code, or the Python implementation…
Could it be there are other .dll files in that directory that this .dll depends on?
I have tried the following commands and they don’t solve the issue:
os.chdir("D:/Programs/libarchive/bin")
os.add_dll_directory("D:/Programs/libarchive/bin")
And no, there is only one .dll in that directory:
PS D:Programslibarchivebin> (gci).fullname
D:Programslibarchivebinarchive.dll
D:Programslibarchivebinbsdcat.exe
D:Programslibarchivebinbsdcpio.exe
D:Programslibarchivebinbsdtar.exe
PS D:Programslibarchivebin>
So how can I fix this?