将 ctype 字节数组转换为字节
Posted
技术标签:
【中文标题】将 ctype 字节数组转换为字节【英文标题】:Convert ctype byte array to bytes 【发布时间】:2013-03-13 04:53:10 【问题描述】:我有一个这样定义的 ctypes 数组:
buff= (c_ubyte*buff_size)()
用数据填充缓冲区后,我需要以字节格式保存这些数据。现在我这样做如下:
buff= [n for n in buff]
buff = ''.join(map(chr, buff))
这样做的问题是它在将其转换回单字节字符串之前将其转换为 4 字节(或任何字节数)的 int,这会浪费大量 CPU。
如何将 ctypes 缓冲区直接转换为字节?我不想为自己保存一份副本,因为无论如何我都必须做一份副本,因为我无法保留原始缓冲区。 python 对这些东西有强制转换功能吗?
谢谢。
【问题讨论】:
你最初是如何将数据输入“buff”的? 【参考方案1】:如果您确实想要一份副本,您可以使用bytearray
:
>>> buff = (c_ubyte * 4)(*[97,98,99,100])
>>> bs = bytearray(buff)
>>> bs
bytearray(b'abcd')
>>> str(bs)
'abcd'
编辑:
对于 2.6 之前的 Python 版本缺少
bytearray
,您可以 请改用以下方法之一:cast(buff, c_char_p).value
buffer(buff)[:]
如果你想共享同一个缓冲区,你可以创建一个c_char
数组:
>>> buff2 = (c_char * len(buff)).from_buffer(buff)
>>> buff2.value # string copy
'abcd'
>>> buff2[:] = 'efgh'
>>> buff[:] # modified original
[101, 102, 103, 104]
编辑:
from_buffer
类方法是在 2.6 中添加的。在以前的版本中,您 可以使用cast
:buff2 = cast(buff, POINTER(c_char * len(buff)))[0]
您不使用c_char
数组是否有原因?我了解您是否需要将其作为数字数组和字符串来使用。
附录:
第二种方法更像是“强制转换”,因为它不复制缓冲区。第一种方法会被复制两次,一次是创建bytearray
,另一次是创建str
(bytes
是str
在2.x 中的别名)。但是 bytearray
有字符串方法,可能就是你所需要的;它基本上是 3.x bytes
的可变版本。
c_char
是 C char
类型。乘以一个数组,它是一个可变的字节缓冲区,就像您当前的 c_ubyte
数组一样。但是,它可能比 c_ubyte
更方便,因为它具有返回 Python 字节字符串的 value
和 raw
描述符。它还将索引和迭代作为单个字符字节字符串而不是整数。
如果函数将修改它,你不应该做的是从 Python 字符串创建一个 c_char_p
- 一个指向字符数据的指针。 Python 字符串对象是不可变的;如果你修改他们的缓冲区,你会得到奇怪的错误。我最近在那个话题上answered a question。
【讨论】:
第一个解决方案有效,但我不得不使用字节(bytearray(buff)),因为没有一个单独工作。我不使用 c_char 的原因;对于一个我仍然需要转换为字节,其次,我认为 c_char 应该是不可变的,所以我将无法修改我的 dll 中的缓冲区。尽管从 ctypes 文档中我不清楚这里认为什么是可变的。 哪里提到 bytes() 和 bytearray() 复制对象?因为我仍然在使用第二种方法时遇到问题。使用 '((ctypes.c_char * len(buff)).from_buffer(buff)).raw' 我得到 '"TypeError: expected a writeable buffer object"' 并使用 '.value' 来切断缓冲区,可能在第一个 \00。 我必须做 from_buffer_copy,否则它会崩溃。谢谢!value
将在 null 处切断。当库将空终止字符串写入缓冲区时,它很有用。 buff
是如何创建为只读的?如果它不是缓冲区(例如(c_char * 4).from_buffer([1,2,3,4])
)或缓冲区是只读的或无法说明它有多少段(应该只有 1 个段),则 PyObject_AsWriteBuffer
会引发该异常。
@michael,仅供参考,memoryview
替换 PY3 中的 buffer
,因此等效转换为 memoryview(buff).tobytes()
,但更简单地说,它只是 bytes(buff)
。以上是关于将 ctype 字节数组转换为字节的主要内容,如果未能解决你的问题,请参考以下文章