报错信息:ctypes.string_at SystemError: Negative size
原因
调用函数 ctypes.string_at(ptr, size)
的时候,size
参数或小于0,或者太大,大于了 int 类型的表示范围,结果导致了函数报错。
修正
但是调用 so 文件的 C API 返回的数据就是这么大,总不能只读取一半数据吧。
所以,解决方案就是增加一个函数,返回 ptr
参数偏移后的指针。这样就可以分段的读取原来 ptr
指向的内存空间了。
import io
import ctypes
from loguru import logger
#import hashlib
# 加载动态库
lib = ctypes.CDLL("./libmodelpre.so")
lib.unpack.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.POINTER(ctypes.c_ulong)]
lib.unpack.restype = ctypes.c_void_p
lib.free_memory.argtypes = [ctypes.c_void_p]
lib.free_memory.restype = None
lib.range.argtypes = [ctypes.c_void_p, ctypes.c_ulong]
lib.range.restype = ctypes.c_void_p
def unpack(self, sslpath, filepath, iv="", md5=""):
# 将文件路径转换为 C 字符串
c_file_path = ctypes.c_char_p(filepath.encode())
c_ssl_path = ctypes.c_char_p(sslpath.encode())
c_iv = ctypes.c_char_p(iv.encode())
c_md5 = ctypes.c_char_p(md5.encode())
# 定义整数变量,用于接收文件长度
file_length = ctypes.c_ulong()
# 调用 C API 函数,并获取返回的文件内容指针
# TODO 在 C API 里面判断 c_iv/c_md5 是不是 empty ?
file_content_ptr = lib.unpack(c_ssl_path, c_file_path, c_iv, c_md5, ctypes.byref(file_length))
logger.info("file length: {}".format(file_length.value))
if file_length.value <= 0:
lib.free(file_content_ptr)
return None
bio = io.BytesIO()
# 将文件内容指针转换为 Python 字符串
logger.info("get content ...")
step = 2 ** 30
for i in range(0, file_length.value, step):
size = min(step, file_length.value - i)
logger.info("i + step = {}".format(i + size))
ptr = lib.range(file_content_ptr, i)
file_content = ctypes.string_at(ptr, size)
bio.write(file_content)
#file_content = ctypes.string_at(file_content_ptr, 1024)
logger.info("get content ok")
# 释放返回的文件内容指针
logger.info("free ...")
lib.free_memory(file_content_ptr)
logger.info("free ok")
bio.seek(0)
return bio
注意⚠️:释放内存的时候,lib.free_memory 函数应该是 void*
的,而不应该是 char*
的,都则会报错
invalid pointer error
参考:https://devpress.csdn.net/python/63045c69c67703293080bd32.html