python3中的编码/解码(伯克利数据库记录)

时间:2019-03-16 21:53:34

标签: python c++ encoding binary-data berkeley-db

我有一个预先存在的伯克利数据库,可以用C ++编写的程序进行读写。我需要回避使用该程序,并直接使用python直接写入数据库。

我可以这样做,但是花了一些时间试图正确编码我的数据,使其格式正确,然后可以由原始C ++程序读取。实际上,当我知道值是什么时,我不知道如何解码现有数据。

数据库中键值对的键应为时间戳,格式为YYYYMMDDHHmmSS。值应该是五个双精度值,然后将一个int混在一起,这意味着(根据C ++程序的源代码)以下结构(?)DVALS

typedef struct
{
  double d1;
  double d2;
  double d3;
  double d4;
  double d5;
  int i1;
} DVALS;

作为键值对的值写入数据库,如下所示:

DBT data;
memset(&data, 0, sizeof(DBT));

DVALS dval;
memset(&dval, 0, sizeof(DVALS));
data.data = &dval;
data.size = sizeof(DVALS);

db->put(db, NULL, &key, &data, 0);

幸运的是,我知道值是多少。因此,如果我从命令行运行

db_dump myfile

最终记录是:

323031393033313431353533303000
ae47e17a140e4040ae47e17a140e4040ae47e17a140e4040ae47e17a140e40400000000000b6a4400000000000000000

使用python的bsddb3模块,我还可以拉出该记录:

from bsddb3 import db
myDB = db.DB()
myDB.open('myfile', None, db.DB_BTREE)
cur = myDB.cursor()
kvpair = cur.last()

现在,kvpair拥有以下信息:

(b'20190314155300\x00', b'\xaeG\xe1z\x14\x0e@@\xaeG\xe1z\x14\x0e@@\xaeG\xe1z\x14\x0e@@\xaeG\xe1z\x14\x0e@@\x00\x00\x00\x00\x00\xb6\xa4@\x00\x00\x00\x00\x00\x00\x00\x00')

时间戳很容易阅读,在这种情况下,实际值如下:

d1 = d2 = d3 = d4 = 32.11
d5 = 2651
i1 = 0

由于'\ xaeG \ xe1z \ x14 \ x0e @@'序列重复了4次,我认为它对应于值32.11

所以我认为我的问题可能只是关于编码/解码,但也许还有更多问题,因此是背景故事。

kvpair[1].decode('utf-8')

使用各种编码只会产生类似于以下的错误:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xae in position 0: invalid start byte

1 个答案:

答案 0 :(得分:2)

值数据是二进制的,因此可以使用Python的struct模块将其解压缩。

>>> import struct
>>> bs = b'\xaeG\xe1z\x14\x0e@@\xaeG\xe1z\x14\x0e@@\xaeG\xe1z\x14\x0e@@\xaeG\xe1z\x14\x0e@@\x00\x00\x00\x00\x00\xb6\xa4@\x00\x00\x00\x00\x00\x00\x00\x00'
>>> len(bs)
48
>>> struct.unpack('<5di4x', bs)
(32.11, 32.11, 32.11, 32.11, 2651.0, 0)

struct.unpack带有两个参数:format specifier,用于定义数据格式和类型以及要解压缩的数据。格式'<5di4x'描述:

  • <:小端顺序
  • 5d:五个双打(每个8个字节)
  • i:一个带符号的整数(4个字节; I表示无符号)
  • 4x:四个填充字节

可以使用struct.pack以相同的方式打包数据。

>>> nums = [32.11, 32.11, 32.11, 32.11, 2651, 0]
>>> format_ = '5di4x'
>>> packed = struct.pack(format_, *nums)
>>> packed == bs
True
>>>