Свързвам се с външна библиотека, използваща ctypes. Тази библиотека връща ми двоичен буфер. Интерфейсът изглежда така:
int getBuff(unsigned char **buf, int *len);
Библиотеката изнася и дистрибутор, така че аз мога да освободя буфера, когато свърша с него, но този аспект не представлява проблем за мен, така че не мисля, че трябва да го покриваме.
В моя ctypes код представлявам buf
аргумент като c_void_p
, Бих искал да копирам този буфер в един байт обект възможно най-ефективно.
В момента имам:
data = bytes(bytearray(ctypes.cast(buf, ctypes.POINTER(ctypes.c_ubyte*len.value))[0]))
където buf
е c_void_p
и len
е c_int
.
Както разбирам, това прави две копия. Веднъж към обектът bytearray, а след това отново към обекта на байта.
Как мога да направя това само с едно копие?
Сегашните ми усилия са съсредоточени върху Python 2, но след време ще трябва да го подкрепя и за Python 3.
Отговори:
6 за отговор № 1Очевидно можете да нарязвате ctypes указател. Не c_void_p
, c_char_p
, или c_wchar_p
, но POINTER
типове работа. За POINTER(c_char)
, нарязвайки го bytes
:
data = ctypes.POINTER(ctypes.c_char).from_buffer(buf)[:len.value]
Благодарение на eryksun за това. Също така не е ясно защо buf
е c_void_p
вместо да е вече POINTER(c_char)
, (За POINTER(c_char)
, кодът ще бъде справедлив buf[:len.value]
.)
За получаване bytes
от общия обект, който поддържа протокола на буфера, memoryview(...).tobytes()
включва по-малко копие от bytes(bytearray(...))
:
data = memoryview(ctypes.cast(buf, ctypes.POINTER(ctypes.c_ubyte*len.value))[0]).tobytes()
Това е съвместимо с Python 2 и Python 3.
Имайте предвид, че buf
тук трябва да има указател към буфера, а не указател към указател към буфера. getBuff
отнема указател към показалеца (толкова вероятно byref(buf)
).