Я работаю над проектом с участием BitTorrent, где я получаю бит-поле в виде строки python. Например:
bitfield = "000001110100111000110101100010"
Я хотел бы иметь возможность преобразовать строку python в формат, чтобы он мог быть вставлен как есть в столбце varbinary (max) базы данных MSSQL с использованием PYODBC. Если я попытаюсь вставить его как строку, как есть, он, конечно, жалуется на ошибку незаконного преобразования.
Примечание. PYODBC ожидает байтовый массив или буфер в качестве входных данных для поля varbinary в соответствии с их документацией.
Мы ценим любые предложения.
Предполагая, что вы используете последнюю версию python, вы можете использовать стандартный struct
модуль библиотеки и функцию bin
. Вот краткий пример:
con = pyodbc.connect("...")
con.execute("CREATE TABLE bin_test ( bin_col varbinary(max) )")
con.execute("INSERT INTO bin_test VALUES (?)",
(int("000001110100111000110101100010", 2),))
result = con.execute("SELECT * FROM bin_test").fetchone()
bin(struct.unpack(">I", result[0])[0])
Результатом окончательного утверждения является
'0b1110100111000110101100010'
который является исходным битовым полем (с удалением ведущих нулей).
Документацию для модуля struct можно найти на docs.python.org. Документация для функции bin также доступна в том же месте.
Прежде чем я получу код, я хотел бы сделать одну рекомендацию: значение "битпотока" не является длиной, которую можно разделить на байты. Я бы предположил, что в любое время, когда вы имеете дело с битовыми строками, вы выражаете их в размерах байтов (например, если len (битполе)% 8! = 0: print 'Убедитесь, что битовое поле может быть полностью представлено байтами!'), Чтобы убедитесь, что нет никакой двусмысленности в том, как манипулировать полями на разных языках программирования, в разных библиотеках на языках программирования и в разных базах данных. Другими словами, база данных, python, библиотека, которую я собираюсь рекомендовать, и т.д. Все собираются либо хранить, либо представлять этот битаррей в виде массива байтов. Если предоставленная битаррей не делит равномерно на байты, произойдет одна из трех вещей: 1) Будет поднята ошибка (это оптимистично). 2) битаррей будет автоматически-магически оставлен. 3) битаррей будет автоматически магически правильно дополнен.
Я бы рекомендовал использовать библиотеку bitstring. Для этой цели я использовал python-bitstring. Я не нашел времени, чтобы разобраться с ODBC здесь, но идея в основном такая же, и использует srgerg ответ:
Примеры:
#!/usr/bin/python
import pymssql
from binascii import hexlify
from bitstring import BitArray
dbconninfo = {'host': 'hostname', 'user': 'username', 'password': 'secret', 'database': 'bitexample', 'as_dict': True}
conn = pymssql.connect(**dbconninfo)
cursor = conn.cursor()
bitfield = "000001110100111000110101100010"
ba = BitArray(bin=bitfield)
print '%32d (bitfield -> BitArray -> int)' % ba.int
cursor.execute("CREATE TABLE bin_test (bin_col varbinary(max) )")
cursor.execute("INSERT INTO bin_test values (%s)", (ba.int,))
cursor.execute("SELECT bin_col FROM bin_test")
results = cursor.fetchone()['bin_col'] # results now contains binary packed data '\x01\xd3\x8db'
conn.rollback()
results_int = int(hexlify(results),16)
print '%32d (bitfield -> BitArray -> int -> DB (where data is binary packed) -> unpacked with hexlify -> int)' % results_int
print '%32s (Original bitfield)' % bitfield
from_db_using_ba_hexlify_and_int_with_length = BitArray(int=int(hexlify(results),16), length=30).bin
print '%32s (From DB, decoded with hexlify, using int to instantiate BitArray, specifying length of int as 30 bits, out as bin)' %
from_db_using_ba_hexlify_and_int_with_length
from_db_using_ba_hex = BitArray(hex=hexlify(results)).bin # Can't specify length with hex
print '%32s (From DB, decoded with hexlify, using hex to instantiate BitArray, can not specify length, out as bin)' % from_db_using_ba_hex
from_db_using_ba_bytes_no_length = BitArray(bytes=results).bin # Can specify length with bytes... that next.
print '%32s (From DB, using bytes to instantiate BitArray, no length specified, out as bin)' % from_db_using_ba_bytes_no_length
from_db_using_ba_bytes = BitArray(bytes=results,length=30).bin
print '%32s (From DB, using bytes to instantiate BitArray, specifying length of bytes as 30 bits, out as bin)' % from_db_using_ba_bytes
from_db_using_hexlify_bin = bin(int(hexlify(results),16))
print '%32s (from DB, decoded with hexlify -> int -> bin)' % from_db_using_hexlify_bin
from_db_using_hexlify_bin_ba = BitArray(bin=bin(int(hexlify(results),16))).bin
print '%32s (from DB, decoded with hexlify -> int -> bin -> BitArray instantiated with bin)' % from_db_using_hexlify_bin
from_db_using_bin = bin(int(results,16))
print '%32s (from DB, no decoding done, using bin)' % from_db_using_bin
Результатом этого является:
30641506 (bitfield -> BitArray -> int)
30641506 (bitfield -> BitArray -> int -> DB (where data is binary packed) -> unpacked with hexlify -> int)
000001110100111000110101100010 (Original bitfield)
000001110100111000110101100010 (From DB, decoded with hexlify, using int to instantiate BitArray, specifying length of int as 30 bits, out as bin)
00000001110100111000110101100010 (From DB, decoded with hexlify, using hex to instantiate BitArray, can not specify length, out as bin)
00000001110100111000110101100010 (From DB, using bytes to instantiate BitArray, no length specified, out as bin)
000000011101001110001101011000 (From DB, using bytes to instantiate BitArray, specifying length of bytes as 30 bits, out as bin)
0b1110100111000110101100010 (from DB, decoded with hexlify -> int -> bin)
0b1110100111000110101100010 (from DB, decoded with hexlify -> int -> bin -> BitArray instantiated with bin)
Traceback (most recent call last):
File "./bitexample.py", line 38, in <module>
from_db_using_bin = bin(int(results,16))
ValueError: invalid literal for int() with base 16: '\x01\xd3\x8db'
Обратите внимание, что, поскольку у вас нет битовой строки, которая может быть напрямую разбита на байты (это строка, представляющая 30 бит), единственный способ получить ту же строку - указать длину, и даже тогда результаты не были в зависимости от того, как был создан экземпляр BitArray.
"{:030b}".format(struct.unpack(">I", result[0])[0])
что должно привести к'000001110100111000110101100010'
.