我试图有选择地自动从许多 7zip 文件中提取文件,通常的
patool
和 pyunpack
等不允许选择要提取的文件。 py7zr
似乎提供了该功能,但我发现提取单个文件效率极低。
我在手动制作此 Google 查询后发现
libarchive-c
:
https://www.google.com/search?q=%22python%22+%227z%22+-patool+-pyunpack+-py7zr&tbs=li:1
在垃圾中筛选,它仍然会返回。
我安装了libarchive
的
此版本,我在此处下载了适用于Windows 10 x64的二进制文件。
我将libarchive包中的文件解压到D:\Programs\libarchive。
一开始我什至无法导入
libarchive
:
In [20]: import libarchive
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Input In [20], in <cell line: 1>()
----> 1 import libarchive
File C:\Program Files\Python310\lib\site-packages\libarchive\__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 Files\Python310\lib\site-packages\libarchive\entry.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 Files\Python310\lib\site-packages\libarchive\ffi.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 Files\Python310\lib\ctypes\__init__.py:452, in LibraryLoader.LoadLibrary(self, name)
451 def LoadLibrary(self, name):
--> 452 return self._dlltype(name)
File C:\Program Files\Python310\lib\ctypes\__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
找出问题所在非常容易,至少对我来说是这样。正是因为这一行:
libarchive_path = os.environ.get('LIBARCHIVE') or find_library('archive')
它会搜索环境变量来归档libarchive库的路径,但我下载的是.zip包而不是安装程序,它没有设置环境变量,所以第一个命令返回
None
。当然这意味着第二个命令也失败了。
所以我必须手动提供正确的路径。它没有详细记录,至少我还没有找到它,但紧接在它下面的行是:
libarchive = ctypes.cdll.LoadLibrary(libarchive_path)
这意味着该路径应该是.dll路径,所以我将其更改为:
libarchive_path = "D:/Programs/libarchive/bin/archive.dll"
但我还是无法导入
libarchive
:
FileNotFoundError: Could not find module 'D:\Programs\libarchive\bin\archive.dll' (or one of its dependencies). Try using the full path with constructor syntax.
我搜索了这个错误,发现了很多不相关的信息。我发现很多类似的帖子:Can't import dll module in Python
但是它们都没有帮助,因为我提供了绝对路径,而它们都在处理相对路径。
所以消息的第一部分是
False
,一定不是这样的,文件一定是确实找到了,或者库代码中有严重的错误,或者Python实现......
难道这个.dll依赖的目录下还存在其他.dll文件?
我已尝试以下命令,但没有解决问题:
os.chdir("D:/Programs/libarchive/bin")
os.add_dll_directory("D:/Programs/libarchive/bin")
不,该目录中只有一个 .dll:
PS D:\Programs\libarchive\bin> (gci).fullname
D:\Programs\libarchive\bin\archive.dll
D:\Programs\libarchive\bin\bsdcat.exe
D:\Programs\libarchive\bin\bsdcpio.exe
D:\Programs\libarchive\bin\bsdtar.exe
PS D:\Programs\libarchive\bin>
那么我该如何解决这个问题?
我使用这个程序来查找任何可执行文件导入的.dll文件:
import json
import os
import subprocess
def get_dependencies(exe):
return [
i["Name"]
for i in
json.loads(
subprocess.run(
["D:/Programs/Dependencies_x64_Release/Dependencies.exe", "-json", "-imports", exe],
capture_output=True,
text=True
).stdout
)["Imports"]
]
dependencies = get_dependencies("D:/Programs/libarchive/bin/archive.dll")
.dll 文件导入以下文件:
['bcrypt.dll',
'libcrypto-1_1-x64.dll',
'KERNEL32.dll',
'VCRUNTIME140.dll',
'api-ms-win-crt-runtime-l1-1-0.dll',
'api-ms-win-crt-heap-l1-1-0.dll',
'api-ms-win-crt-string-l1-1-0.dll',
'api-ms-win-crt-time-l1-1-0.dll',
'api-ms-win-crt-utility-l1-1-0.dll',
'api-ms-win-crt-stdio-l1-1-0.dll',
'api-ms-win-crt-convert-l1-1-0.dll',
'api-ms-win-crt-locale-l1-1-0.dll',
'api-ms-win-crt-environment-l1-1-0.dll',
'api-ms-win-crt-filesystem-l1-1-0.dll']
我试图找到哪些不存在:
for dll in dependencies:
if not os.path.isfile("C:/Windows/System32/" + dll):
print(dll)
libcrypto-1_1-x64.dll
api-ms-win-crt-runtime-l1-1-0.dll
api-ms-win-crt-heap-l1-1-0.dll
api-ms-win-crt-string-l1-1-0.dll
api-ms-win-crt-time-l1-1-0.dll
api-ms-win-crt-utility-l1-1-0.dll
api-ms-win-crt-stdio-l1-1-0.dll
api-ms-win-crt-convert-l1-1-0.dll
api-ms-win-crt-locale-l1-1-0.dll
api-ms-win-crt-environment-l1-1-0.dll
api-ms-win-crt-filesystem-l1-1-0.dll
看来我需要下载
libcrypto-1_1-x64.dll
,但是其他文件是什么?它们似乎不太可能丢失,但它们不在 System32 文件夹中。
感谢这个评论我能够解决这个问题。
所以我使用这个程序来查找任何可执行文件的依赖关系,我使用以下代码来过滤掉不必要的信息:
import json
import os
import subprocess
def get_dependencies(exe):
return [
i["Name"]
for i in
json.loads(
subprocess.run(
["D:/Programs/Dependencies_x64_Release/Dependencies.exe", "-json", "-imports", exe],
capture_output=True,
text=True
).stdout
)["Imports"]
]
dependencies = get_dependencies("D:/Programs/libarchive/bin/archive.dll")
我得到了这个:
['bcrypt.dll',
'libcrypto-1_1-x64.dll',
'KERNEL32.dll',
'VCRUNTIME140.dll',
'api-ms-win-crt-runtime-l1-1-0.dll',
'api-ms-win-crt-heap-l1-1-0.dll',
'api-ms-win-crt-string-l1-1-0.dll',
'api-ms-win-crt-time-l1-1-0.dll',
'api-ms-win-crt-utility-l1-1-0.dll',
'api-ms-win-crt-stdio-l1-1-0.dll',
'api-ms-win-crt-convert-l1-1-0.dll',
'api-ms-win-crt-locale-l1-1-0.dll',
'api-ms-win-crt-environment-l1-1-0.dll',
'api-ms-win-crt-filesystem-l1-1-0.dll']
我很快就确定了
libcrypto-1_1-x64.dll
丢失了,所以我从这里下载了它,我提取了存档并将.dll复制粘贴到C:\Windows\System32目录中,问题就解决了。