如何在python 3中有效地将原始字节写入numpy数组数据

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在python 3中有效地将原始字节写入numpy数组数据相关的知识,希望对你有一定的参考价值。

当将一些旧的python 2代码迁移到python 3时,我遇到了一些问题,即从字节对象填充结构化的numpy数组。

我有一个解析器,为我可能遇到的每种数据结构类型定义了一个特定的dtype。通常,由于给定的数据结构可能具有可变长度或可变类型的字段,因此这些字段已在numpy数组中表示为对象dtype(np.object #alternatively np.dtype('O'))的字段。

首先通过填充fixed-dtype字段从字节(或bytearray)获得数组。此后,可以使用前面的固定字段中的信息来构建任何子数组(包含在“对象”字段中)的dtype。

这里是在python 2中工作的此过程的一部分示例(仅处理fixed-dtype字段)。请注意,我们有一个名为'nSamples'的字段,大概可以告诉我们所指向的数组的长度。数组的'samples'字段,它将被解释为形状为(2,)和dtype sampleDtype的numpy数组:

fancyDtype = np.dtype([('blah',     '<u4'),
                       ('bleh',      'S5'),
                       ('nSamples', '<u8'),
                       ('samples',    'O')])

sampleDtype = np.dtype([('sampleId', '<u2'),
                        ('val',      '<f4')])

bytesFromFile = bytearray(
    b'*x00x00x00hellox02x00x00x00x00x00x00x00xd0xb5'
    b'x14_xa1x7fx00x00"x00x00x00x80?]x00x00x00xa0@')

arr = np.zeros((1,), dtype=fancyDtype)
numBytesFixedPortion = 17

# Start out by just reading the fixed-type portion of the array
arr.data[:numBytesFixedPortion] = bytesFromFile[:numBytesFixedPortion]
memoryview(arr.data)[:numBytesFixedPortion] = bytesFromFile[:numBytesFixedPortion]

这里的最后两个语句都在python 2.7中起作用。

值得注意的是,如果我键入

arr.data

我得到<read-write buffer for 0x7f7a93bb7080, size 25, offset 0 at 0x7f7a9339cf70>,它告诉我这是一个缓冲区。显然,memoryview(arr.data)返回一个memoryview对象。

这两个语句在python 3.6中都引发以下异常:

NotImplementedError: memoryview: unsupported format T{I:blah:5s:bleh:=Q:nSamples:O:samples:}

这告诉我numpy返回的访问类型是data,而不是memoryview。它还告诉我buffer在python 2.7中有效,但在python 3.6中不适用。

[我在numpy的问题跟踪器中发现了类似的问题:memoryviews但是,该问题已迅速关闭,numpy开发人员指出这是https://github.com/numpy/numpy/issues/13617中的错误。由于ctypes是内置函数,因此我对仅对其进行更新以得到修复的希望就放弃了。

我终于偶然发现了一个可行的解决方案,尽管它花费的时间大约是python 2.7方法的两倍。它是:

ctypes

一位同事还建议尝试使用此解决方案:

import struct
struct.pack_into(
    'B' * numBytesFixedPortion,  # fmt
    arr.data,                    # buffer
    0,                           # offset
    *buf[:numBytesFixedPortion]  # unpacked byte values
)

但是,在执行此操作时,我得到了例外:

arrView = arr.view('u1')
arrView[:numBytesFixedPortion] = buf[:numBytesFixedPortion]

请注意,我在python 2.7和3.6中均收到此异常。似乎numpy不允许在具有任何File "/home/tintedFrantic/anaconda2/envs/py3/lib/python3.6/site-packages/numpy/core/_internal.py", line 461, in _view_is_safe raise TypeError("Cannot change data-type for object array.") TypeError: Cannot change data-type for object array. 字段的阵列上进行查看。 (此外:通过注释掉numpy代码中对对象类型字段的检查,我能够使numpy正确地做到这一点,尽管这似乎是一种危险的解决方案(也不是一种非常可移植的解决方案)。)

我也尝试过创建单独的数组,一个数组具有fixed-dtype字段,另一个数组与object-dtype字段,然后使用object合并它们。失败的原因是我不记得一条神秘的消息。

我有点茫然。我只想向numpy数组的基础内存写入一些任意字节,然后高效地进行操作。这似乎并不难,但是我还没有找到一种好的方法。我想要一个也不是hack的解决方案,因为这将进入需要高可靠性的系统。如果没有更好的方法,我将使用numpy.lib.recfunctions.merge_arrays解决方案,但我希望那里的人知道更好的方法。顺便说一句,不使用object-dtype字段不是一个可行的选择,因为这样做的成本太高了。

[如果有问题,我正在python 2.7中使用numpy 1.16.2,对于python 3.6使用1.17.4。

当将一些旧的python 2代码迁移到python 3时,我遇到了一些问题,即从字节对象填充结构化的numpy数组。我有一个解析器,为每种类型的...定义一个特定的dtype ...

答案

根据@nawsleahcimnoraa的建议,我发现在python 3.3+中(而不是在python 2.7中),在我的python 3环境中由struct.pack_into()返回的memoryview对象具有arr.data方法。因此,我可以这样做

以上是关于如何在python 3中有效地将原始字节写入numpy数组数据的主要内容,如果未能解决你的问题,请参考以下文章

如何从 BluetoothChat 的输入/输出流中读取/写入原始十六进制字节?

如何有效地将结构向量写入文件?

在 C# 中有效地将字符串转换为字节数组(不使用编码)[重复]

如何实时读取/写入原始音频数据(使用python)?

在单臂霓虹灯寄存器中有效地将 8 位数字扩展到 12 位

如何有效地将 BSTR 复制到 wchar_t[]?