2011-11-04 27 views
1

私はBitTorrentに関するプロジェクトに取り組んでいます。そこではビットフィールドをPython文字列として受け取ります。例えば:PYODBCを使用してMSSQLのVarBinary(MAX)にBitTorrentビットフィールドを挿入する

ビットフィールド=「000001110100111000110101100010」

IはPYODBCを使用してMSSQLデータベースのVARBINARY(MAX)列になるように挿入することができるような形式にPythonの文字列を変換できるようにしたいと思い。私は文字列としてそれを挿入しようとすると、もちろん、それは違法変換エラーの文句を言う。

メモ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' 

です。

structモジュールのドキュメントは、docs.python.orgにあります。 bin関数のドキュメントは、the same placeでも入手できます。

+0

先頭の0を保持する方法はありますか?それはビットフィールドなので重要です。 – Slruh

+2

あなたが知っているビット数がある場合は、あらかじめPython文字列フォーマットを使用して文字列をゼロで埋め込むことができます。たとえば、30ビットが必要な場合は、上のサンプルコードの最後の行を '" {:030b} "に置き換えることができます(format.unpack("> I "、result [0])[0] ) '' 000001110100111000110101100010 ''になります。 – srgerg

2

コードを作成する前に、私は1つの推奨をしたいと思います。「ビットフィールド」の値は、バイトに分割できる長さではありません。私はあなたがビット列を扱っているときはいつでも、あなたはそれらをバイトの大きさで成長させることを提案したいと思います(例えばlen(ビットフィールド)%8!= 0:print 'ビットフィールドが完全にバイトで表現できることを確認してください)異なるプログラミング言語、プログラミング言語内の異なるライブラリ、および異なるデータベースでフィールドがどのように操作されるかにあいまいさがないことを確認してください。言い換えれば、データベース、Python、私が推薦しようとしているライブラリなどはすべて、このビット配列を格納するか、バイト配列の形で表現できるかのどちらかです。提供されたビット配列が均等にバイトに分割されない場合、次の3つのうちの1つが発生します。 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がどのようにインスタンス化されたかで終わります。

+0

最後の一言の注意 - 私はpymssqlを使ってvarbinaryフィールドにIPアドレスを格納しようとしています。 INSERT問合せにintを渡すと(srgergとmy postの両方で)、INSERT問合せに長さが31ビットを超えると問題が発生します(最初のビットが符号を格納し、残りのビットが格納可能です32ビットすべてを使用すると、予期しない整数値がデータベースにプッシュされる可能性があります)。この問題を回避するには、整数を最初にパックし、ライブラリを使用してintをパックバイナリに変換するのではなく、 'INSERT'ステートメントでバイナリパックされた値を渡します。 –

関連する問題