2011-11-04 56 views
1

我正在研究一个涉及BitTorrent的项目,在那里我接收一个位域作为python字符串。例如:使用PYODBC在MSSQL中将BitTorrent位域插入到VarBinary(MAX)中

位字段=“000001110100111000110101100010”

我想能够蟒字符串转换成格式,以便它可以被插入作为是成使用PYODBC一个MSSQL数据库的VARBINARY(max)列。如果我试图按字符串的形式插入它,它当然会抱怨非法转换错误。

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

任何建议,将不胜感激。

回答

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找到结构模块的文档。 bin函数的文档也可在the same place处获得。

+0

有没有办法保留前导0?由于它是一个位域,它们很重要。 – Slruh

+2

如果您知道应该提前多少位,则可以使用python字符串格式将字符串填充为零。例如,如果应该有30位,那么可以用'“{:030b}”替换上面示例代码中的最后一行。format(struct.unpack(“> I”,result [0])[0] )'这应该导致'000001110100111000110101100010'。 – srgerg

2

在我编写代码之前,我想提出一个建议:'位域'值不是可以分成字节的长度。我建议,无论何时您处理位串,您都可以按字节大小增长它们(例如,如果len(位域)%8!= 0:print'确保位域可以完全以字节表示!')确保在不同的编程语言,编程语言中的不同库以及不同的数据库中操作字段的方式不存在歧义。换句话说,数据库,python,我要推荐的库等都将存储或能够以字节数组的形式表示这个bitarray。如果提供的比特阵不能均匀地分成字节,将发生以下三种情况之一: 1)会出现错误(这是乐观的) 2)比特数将自动奇迹地左填充。 3)该bitarray将自动魔术右垫。

我建议使用某种类型的位串库。为此我使用了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。

+0

谨慎的一句话 - 我一直在尝试使用pymssql来存储varbinary字段中的IP地址。如果将一个int(如上面在srgerg和我的帖子中所做的那样)传递给INSERT查询,那么如果长度大于31位,则可能会遇到问题(对于python int,第一位存储符号,其余位可以存储值,因此使用全部32位可能会导致意外的整数值被推送到数据库中)。为了避免这些问题,请首先打包整数,然后在“INSERT”语句中传递二进制打包值,而不是依赖库来将int转换为打包二进制文件。 –

相关问题