使用PYODBC将BitTorrent位域插入MSSQL中的VarBinary(MAX)

时间:2011-11-04 02:25:47

标签: python sql-server bittorrent pyodbc

我正在开发一个涉及BitTorrent的项目,在那里我收到一个bitfield作为python字符串。例如:

bitfield =“000001110100111000110101100010”

我希望能够将python字符串转换为格式,以便可以使用PYODBC将其原样插入到MSSQL数据库的varbinary(max)列中。如果我尝试将其作为字符串插入,它当然会抱怨非法的转换错误。

注意PYODBC,根据文档要求将字节数组或缓冲区作为varbinary字段的输入。

任何建议都将不胜感激。

2 个答案:

答案 0 :(得分:2)

假设您使用的是最新版本的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'

这是初始位域(删除了前导零)。

您可以在docs.python.org上找到struct模块的文档。 bin函数的文档也可以在the same place获得。

答案 1 :(得分:2)

在我开始编写代码之前,我想提出一个建议:'bitfield'值不是可以分成字节的长度。我建议你在处理位字符串时,你会以字节大小增长它们(例如,如果len(位域)%8!= 0:print'确保位域可以用字节完全表示!')确保在不同的编程语言,编程语言中的不同库和不同的数据库中如何操作字段没有歧义。换句话说,数据库,python,我将推荐的库等都将存储或能够以字节数组的形式表示这个比特阵列。如果提供的bitarray不能均匀地划分为字节,则会发生以下三种情况之一: 1)会出错,(这很乐观) 2)比特阵列将自动神奇地留下填充。 3)比特阵将自动神奇地填充。

我建议使用某种位串库。我为此目的使用了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's 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的实例化方式。