Кодирование / декодирование (записи базы данных Беркли) в python3 - PullRequest
0 голосов
/ 17 марта 2019

У меня есть уже существующая база данных Беркли, написанная и прочитанная из программы, написанной на 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'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

As '\ 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 Ответ

2 голосов
/ 17 марта 2019

Данные значения являются двоичными, поэтому их можно распаковать с помощью модуля 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 принимает два аргумента: спецификатор формата , который определяет формат и типы данных и данные, подлежащие распаковке. Формат '<5di4x' описывает:

  • <: порядковый порядок байтов
  • 5d: пять двойных (по 8 байт)
  • i: один со знаком int (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
>>> 
...