Encoding/Decoding(伯克利数据库记录)在python3
Encoding/Decoding (Berkeley database records) in python3
我有一个预先存在的 berkeley 数据库写入和读取一个用 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
所以我认为我的问题可能只是关于 encoding/decoding,但也许还有更多,因此是背景故事。
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'\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
takes two arguments: a 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
>>>
我有一个预先存在的 berkeley 数据库写入和读取一个用 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
所以我认为我的问题可能只是关于 encoding/decoding,但也许还有更多,因此是背景故事。
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'\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
takes two arguments: a 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
>>>