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

Encoding/Decoding (Berkeley database records) in python3

本文关键字:伯克利 数据库 记录 解码 编码 Python3      更新时间:2023-10-16

我有一个曾经存在的伯克利数据库,并从C 编写的程序中读取并阅读。我需要避开此程序,然后使用Python直接写入数据库。

我可以做到这一点,但是有一段时间试图正确编码我的数据,以使其以适当的形式进行,然后可以通过原始的C 程序读取。实际上,当我知道值是什么时,我无法弄清楚如何解码现有数据。

数据库中键值对的键应为yyyymmddhhmmss形式的时间戳。这些值应该是五个双打,并将一个插入在一起,我的意思是(从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'20190314155300x00', b'xaeGxe1zx14x0e@@xaeGxe1zx14x0e@@xaeGxe1zx14x0e@@xaeGxe1zx14x0e@@x00x00x00x00x00xb6xa4@x00x00x00x00x00x00x00x00')

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

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

值数据是二进制的,因此可以使用python的struct模块对其进行拆箱。

>>> import struct
>>> bs = b'xaeGxe1zx14x0e@@xaeGxe1zx14x0e@@xaeGxe1zx14x0e@@xaeGxe1zx14x0e@@x00x00x00x00x00xb6xa4@x00x00x00x00x00x00x00x00'
>>> len(bs)
48
>>> struct.unpack('<5di4x', bs)
(32.11, 32.11, 32.11, 32.11, 2651.0, 0)

struct.unpack采用两个参数:一个格式指定符,以定义数据格式和类型以及要解开包装的数据。格式'<5di4x'描述:

  • <:小末日订单
  • 5d:五个双打(每个字节8个)
  • i:一个签名的int(4个字节; I for insigned)
  • 4x:四个垫字节

可以使用struct.pack

可以以相同的方式包装数据
>>> nums = [32.11, 32.11, 32.11, 32.11, 2651, 0]
>>> format_ = '5di4x'
>>> packed = struct.pack(format_, *nums)
>>> packed == bs
True
>>>