2

私は BitTorrent を含むプロジェクトに取り組んでおり、ビットフィールドを Python 文字列として受け取ります。例えば:

ビットフィールド = "000001110100111000110101100010"

Python 文字列をフォーマットに変換して、PYODBC を使用して MSSQL データベースの varbinary(max) 列にそのまま挿入できるようにしたいと考えています。そのまま文字列として挿入しようとすると、もちろん不正な変換エラーになります。

注 PYODBC は、ドキュメントによると、varbinary フィールドの入力としてバイト配列またはバッファーを想定しています。

任意の提案をいただければ幸いです。

4

2 に答える 2

2

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

于 2012-02-10T22:58:14.913 に答える
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 関数のドキュメントも同じ場所にあります。

于 2011-11-04T04:31:31.977 に答える