将外部提供的缓冲区复制到字节的最有效方法是什么

Dav*_*nan 9 python ctypes python-2.7 python-3.x

我正在使用ctypes连接到外部库.这个库给我一个二进制缓冲区.界面如下所示:

int getBuff(unsigned char **buf, int *len);
Run Code Online (Sandbox Code Playgroud)

该库还会导出一个deallocator,以便在完成后可以释放缓冲区,但这方面对我没有任何问题,所以我认为我们不需要覆盖它.

在我的ctypes代码中,我将buf参数表示为c_void_p.我想尽可能有效地将此缓冲区复制到字节对象中.

目前我有:

data = bytes(bytearray(ctypes.cast(buf, ctypes.POINTER(ctypes.c_ubyte*len.value))[0]))
Run Code Online (Sandbox Code Playgroud)

这里bufc_void_plenc_int.

据我了解,这会执行两个副本.一次到bytearray对象,然后再到bytes对象.

我怎么能只用一个副本呢?

我目前的努力集中在Python 2上,但在适当的时候我也需要为Python 3支持这一点.

use*_*ica 6

显然你可以切片ctypes指针.不c_void_p,c_char_pc_wchar_p,但POINTER类型工作.对于a POINTER(c_char),切片它会给你bytes:

data = ctypes.POINTER(ctypes.c_char).from_buffer(buf)[:len.value]
Run Code Online (Sandbox Code Playgroud)

感谢eryksun带来的.此外,还不清楚为什么buf是一个c_void_p而不是已经是一个POINTER(c_char).(对于a 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()
Run Code Online (Sandbox Code Playgroud)

这与Python 2和Python 3兼容.


请记住,buf这里需要是指向缓冲区的指针,而不是指向缓冲区指针的指针.getBuff采用指向指针的指针(很可能byref(buf)).