2011-11-04 4 views
1

저는 BitTorrent와 관련된 프로젝트에서 Python 문자열로 비트 필드를받습니다. 예를 들면 :PYODBC를 사용하여 MSSQL에서 VarBinary (MAX)에 BitTorrent 비트 필드 삽입

비트 필드 = "000001110100111000110101100010"가 삽입 될 수 있도록 PYODBC을 사용하여 MSSQL 데이터베이스의 VARBINARY (최대) 열에 그대로

나는 형식으로 파이썬 문자열을 변환 할 수 있도록하고 싶습니다 . 있는 그대로 문자열을 삽입하려고하면 물론 불법적 인 변환 오류가 발생합니다.

참고 PYODBC는 설명서에 따라 varbinary 필드의 입력으로 바이트 배열 또는 버퍼를 예상합니다.

의견을 보내 주시면 감사하겠습니다.

답변

2

파이썬의 최신 버전을 사용한다고 가정하면 표준 라이브러리 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]) 

마지막 문장의 결과는 (제거 선행 0 포함) 초기 비트 필드 인

'0b1110100111000110101100010' 

입니다 : 여기에 빠른 예입니다.

구조 모듈에 대한 설명서는 docs.python.org에서 찾을 수 있습니다. bin 기능에 대한 문서는 the same place에서도 사용할 수 있습니다.

+0

선두 0을 유지할 방법이 있습니까? 그것은 비트 필드이기 때문에 중요합니다. – Slruh

+2

미리 알고 있어야한다면 파이썬 문자열 형식을 사용하여 문자열을 0으로 채울 수 있습니다. 예를 들어, 30 비트가 있어야한다면 위의 샘플 코드에서 마지막 줄을''{: 030b} '로 바꿀 수있다. format (struct.unpack ("> I", result [0]) [0]) '로 표시되며 결과는'000001110100111000110101100010 '입니다. – srgerg

2

코드를 작성하기 전에 다음과 같은 권장 사항을 작성하고 싶습니다. '비트 필드'값은 바이트로 나눌 수있는 길이가 아닙니다. 나는 당신이 비트 문자열을 다룰 때 언제든지 그것을 제안한다. len (bitfield) % 8! = 0 : print '비트 필드가 바이트로 완전히 표현 될 수 있는지 확인하라!') 다른 프로그래밍 언어, 프로그래밍 언어 내의 다른 라이브러리 및 다른 데이터베이스에서 필드가 조작되는 방법에 모호성이 없도록하십시오. 즉, 데이터베이스, 파이썬, 내가 추천하려고하는 라이브러리 등은 모두이 비트 배열을 저장하거나 바이트 배열 형태로 표현할 수 있습니다. 제공된 비트 배열이 균등하게 바이트로 나누지 않으면 다음 세 가지 중 하나가 발생합니다. 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'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와 내 포스트 모두에서 수행 한 것처럼)를 전달하면 길이가 31 비트를 초과하면 문제가 발생할 수 있습니다 (첫 번째 비트는 부호를 저장하고 나머지 비트는 저장할 수 있음). 값이므로 모든 32 비트를 사용하면 예기치 않은 정수 값이 데이터베이스로 전달 될 수 있습니다. 이 문제를 피하려면 정수를 먼저 패킹하고 라이브러리를 사용하여 int를 packed binary로 변환하는 대신 INSERT 문에 이진 값을 전달합니다. –