【问题标题】:Parsing Binary files that contains BCD (Binary Coded Decimal) values using Python Numpy使用 Python Numpy 解析包含 BCD(二进制编码十进制)值的二进制文件
【发布时间】:2018-11-21 09:28:01
【问题描述】:

我有一个二进制文件,其中包含一些编码为 BCD(二进制编码十进制)的字段。示例如下。

14 75 26 58 87 7F(十六进制格式的原始字节)。

我正在使用 (np.void, 6) 从二进制文件读取和转换,下面是我得到的输出。

b'\x14\x75\x26\x58\x87\x7F'

但我想使用 numpy 将输出作为“14752658877”,不使用填充字符“F”。

下面是代码: 用 open (filename, "rb") as f:

    while True:

        chunk = f.read(chunksize)

        if (chunk):

            dt = np.dtype([('a','b'), ('b', '>i4'), ('c', 'S15'),('d', np.str, 7),
                                   ('e', 'S7'), ('f', np.void, 6)])

            x = np.frombuffer (chunk, dtype=dt)
            print (x)

        else:
            break

此外,输入文件包含许多固定长度的二进制记录。使用 numpy 将其转换并存储为 ascii 文件的有效方法是什么?

【问题讨论】:

  • 显示示例代码。
  • 下面是代码:with open (filename, "rb") as f: while True: chunk = f.read(chunksize) if (chunk): dt = np.dtype([(' a','b'), ('b', '>i4'), ('c', 'S15'),('d', np.str, 7), ('e', 'S7') , ('f', np.void, 6)]) x = np.frombuffer (chunk, dtype=dt) print (x) else: break
  • 请编辑您的原始问题,添加上述代码,保留所有格式和缩进。
  • 嗨,Ricardo,我已经编辑了原始问题以添加代码。
  • F 不是填充字符。它是十六进制值的一部分。

标签: python numpy


【解决方案1】:

我不知道 numpy 是否能以某种方式加速这一点,但可以快速构建一个专门的函数:

fastDict = {16*(i//10)+(i%10):i for i in range(100)}

def bcdToInteger(bcd):
    result = 0
    while bcd and bcd[0] in fastDict:
        result *= 100
        result += fastDict[bcd[0]]
        bcd = bcd[1:]
    if bcd and bcd[0] & 0xf0 <= 0x90:
        result *= 10
        result += bcd[0]>>4
        if bcd[0] & 0xf <= 9:
            result *= 10
            result += bcd[0] & 0x0f
    return result

>>> print (bcdToInteger(b'\x14\x75\x26\x58\x87\x7F'))  # your sequence
14752658877
>>> print (bcdToInteger(b'\x12\x34\xA0'))   # first invalid nibble ends
1234
>>> print (bcdToInteger(b'\x00\x00\x99'))   # and so does an end of string
99
>>> print (bcdToInteger(b'\x1F'))           # a single nibble value
1

只要您继续输入有效的 BCD 字节,它就会将结果乘以 100 并添加两个新数字。只有最后一个字节需要进一步检查:如果最高半字节有效,则迄今为止的结果乘以 10 并添加该半字节。如果最低的半字节也有效,则重复此操作。

fastDict 是为了加快速度。它是一个字典,可以返回从0099 的所有 100 个十六进制字节的正确值,因此实际计算的数量尽可能少。你可以不使用字典,但这意味着你必须在if 块中对每个字节进行比较和计算。

【讨论】:

  • 感谢您的解决方案。我正在使用 binascii.hexlify(bcdvalue).decode('utf-8').rstrip('f') 来获得首选结果。但我正在寻找高效的解决方案,因为我有很多这样的专栏。我们的每日记录量接近 10 亿条记录。
  • @RajKB:嗯,我的解决方案对我来说似乎非常有效。正如您在some otheranswers 中看到的那样,它们使用昂贵的位移和比较每个字节两次;我的代码避免了这种情况。然而,甚至可以使用 C 中的自定义扩展来编写更快的代码,但我不会尝试这样做。
  • 您好,我正在尝试您的解决方案。但是在运行代码时出现以下错误。你能检查一下吗。文件“”,第 7 行,在 bcdToInteger 中,如果 bcd 和 bcd[0] & 0xf0
  • 请忽略以上评论。
  • 是的。非常感谢您的回答。
猜你喜欢
  • 2012-07-25
  • 1970-01-01
  • 2014-02-13
  • 1970-01-01
  • 2020-04-18
  • 1970-01-01
  • 1970-01-01
  • 2018-12-14
  • 2010-10-03
相关资源
最近更新 更多