我无法使用 libmtp 库将 Python 字典作为参数传递给 Cython 函数。
在文件 test.py 中,connect_device() 方法正常工作,连接到设备,并返回映射 LIBMTP_mtpdevice_t 结构的字典,然后我以字典作为参数调用 list_folders() 方法。
我在 C 函数 _list_folders() 内再次将其转换为 LIBMTP_mtpdevice_t 类型,但是当我将其作为参数传递给库函数 LIBMTP_get_folder_list() 时,程序因分段错误而崩溃。
我错过了一些东西,但我不知道是什么。
我希望我说得很清楚,我是 Cython 的新手,希望有人能帮助我找到问题。
谢谢。
测试.py
import mtp_manager as m
def run():
try:
print("\nconnecting device...\n")
dev = m.connect_device()
print("\ndevice connected listing files and folders...\n")
lst = m.list_folders(dev)
print("\n printing list... \n")
print(f"Folder list: {lst}")
except Exception as e:
print(e)
if __name__ == "__main__":
run()
mtp.pyx
def connect_device():
dev_d = None
LIBMTP_Init()
cdef LIBMTP_mtpdevice_t *device
device = LIBMTP_Get_First_Device()
if device is NULL:
print("No MTP devices found.")
return None
try:
dev_ext = {}
dev_ext['name'] = device.extensions.name.decode('utf-8')
dev_ext['major'] = device.extensions.major
dev_ext['minor'] = device.extensions.minor
dev_ext['next'] = <uintptr_t> device.extensions.next
dev_err = {}
dev_err['errornumber'] = device.errorstack.errornumber
dev_err['error_text'] = device.errorstack.error_text.decode('utf-8')
dev_err['next'] = <uintptr_t> device.errorstack.next
dev_storage = {}
dev_storage['id'] = device.storage.id
dev_storage['StorageType'] = device.storage.StorageType
dev_storage['FilesystemType'] = device.storage.FilesystemType
dev_storage['AccessCapability'] = device.storage.AccessCapability
dev_storage['MaxCapacity'] = device.storage.MaxCapacity
dev_storage['FreeSpaceInBytes'] = device.storage.FreeSpaceInBytes
dev_storage['FreeSpaceInObjects'] = device.storage.FreeSpaceInObjects
dev_storage['StorageDescription'] = device.storage.StorageDescription.decode('UTF-8')
dev_storage['VolumeIdentifier'] = device.storage.VolumeIdentifier.decode('UTF-8')
dev_storage['next'] = <uintptr_t>device.storage.next
dev_storage['prev'] = <uintptr_t>device.storage.prev
dev_d = {}
dev_d['object_bitsize'] = device.object_bitsize
dev_d['params'] = <void>device.params
dev_d['usbinfo'] = <void>device.usbinfo
dev_d['maximum_battery_level'] = device.maximum_battery_level
dev_d['default_text_folder'] = device.default_text_folder
dev_d['default_album_folder'] = device.default_album_folder
dev_d['default_music_folder'] = device.default_music_folder
dev_d['default_video_folder'] = device.default_video_folder
dev_d['default_picture_folder'] = device.default_picture_folder
dev_d['default_zencast_folder'] = device.default_zencast_folder
dev_d['default_playlist_folder'] = device.default_playlist_folder
dev_d['default_organizer_folder'] = device.default_organizer_folder
dev_d['cd'] = <void>device.cd
dev_d['cached'] = device.cached
dev_d['next'] = <uintptr_t>device.next
dev_d['extensions'] = dev_ext
dev_d['errorstack'] = dev_err
dev_d['storage'] = dev_storage
except Exception as e:
print(e)
return dev_d
def list_folders(device):
folders = _list_folders(<LIBMTP_mtpdevice_t*> device)
return folders
cdef _list_folders(LIBMTP_mtpdevice_t *device):
if not device:
raise TypeError
cdef LIBMTP_folder_t *folders
#SEGMENTATION FAULT
folders = LIBMTP_Get_Folder_List(device)
...
最后我设法自己解决了这个问题:解决方案很简单,只是不处理设备对象,而是将其隐藏在 cython 模块中:
我的 cython 代码:
# mtp_manager.pyx - Cython code to interact with MTP devices
# distutils: language=cython
# cython: language_level=3
import cython
from libmtp cimport LIBMTP_mtpdevice_t, LIBMTP_Get_Folder_List, \
LIBMTP_Get_Files_And_Folders, LIBMTP_Get_First_Device, \
LIBMTP_Init, LIBMTP_folder_t, LIBMTP_file_t, \
LIBMTP_PTP_ObjectHandles, LIBMTP_Get_Folder_List_For_Storage, \
LIBMTP_device_extension_t, LIBMTP_error_t, LIBMTP_error_number_t, \
LIBMTP_devicestorage_t
from libc.stdint cimport uint32_t, uint16_t, uint64_t, uint8_t, uintptr_t, int
class FileManager(cFileManager):
def __init__(self):
super().__init__()
cdef class cFileManager:
cdef LIBMTP_mtpdevice_t * __device
def __init__(self):
self.__device = self.connect_device()
if not self.__device:
raise TypeError
cdef LIBMTP_mtpdevice_t * connect_device(self):
LIBMTP_Init()
cdef LIBMTP_mtpdevice_t *device
return LIBMTP_Get_First_Device()
def list_folders(self):
return self._list_folders()
cdef _list_folders(self):
cdef LIBMTP_folder_t * folders = LIBMTP_Get_Folder_List(self.__device)
lst = []
while folders:
lst.append(folders.name.decode('UTF-8'))
folders = folders.sibling
return lst
Python代码:
from mtp_file_manager import FileManager
def run():
try:
print("\nconnecting device...\n")
fm = FileManager()
print("\ndevice connected listing files and folders...\n")
print("\n printing list... \n")
print(fm.list_folders())
except Exception as e:
print(e)
if __name__ == "__main__":
run()
我希望它对其他人有用