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

发布于 2024-12-14 00:53:57 字数 304 浏览 4 评论 0原文

我正在开发一个涉及 BitTorrent 的项目,在该项目中我收到一个 python 字符串形式的位字段。例如:

bitfield = "000001110100111000110101100010"

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

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

任何建议将不胜感激。

I'm working on a project involving BitTorrent, where I receive an bitfield as a python string. For example:

bitfield = "000001110100111000110101100010"

I would like to be able to convert the python string into a format so it can be inserted as is into a varbinary(max) column of a MSSQL database using PYODBC. If I try to insert it as a string as is, it of course complains of an illegal conversion error.

Note PYODBC, expects a byte array or buffer as input for a varbinary field according to their documentation.

Any suggestions would be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

給妳壹絲溫柔 2024-12-21 00:53:57

假设您使用的是最新版本的 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 函数的文档也可以在同一个地方找到。

Assuming you're using a recent version of python you can take advantage of the standard library struct module and the bin function. Here's a quick example:

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])

The result of the final statement is

'0b1110100111000110101100010'

which is the initial bitfield (with the leading zeroes removed).

You can find the documentation for the struct module on docs.python.org. The documentation for the bin function is also available at the same place.

<逆流佳人身旁 2024-12-21 00:53:57

在开始编码之前,我想提出一个建议:“位字段”值不是可以分为字节的长度。我建议,每当您处理位字符串时,都以字节大小来增加它们(例如 if len(bitfield)%8 != 0: print 'Make make certain the bitfield can be full returned by bytes!')确保在不同的编程语言、编程语言中的不同库以及不同的数据库中操作字段的方式没有歧义。换句话说,数据库、Python、我要推荐的库等都将存储或能够以字节数组的形式表示这个位数组。如果提供的位数组没有均匀地划分为字节,则会发生以下三种情况之一:
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 的实例化方式。

Before I get to code, I'd like to make one recommendation: The 'bitfield' value isn't a length that can be divided into bytes. I'd suggest that anytime you're dealing with bit strings, you grow them in sizes of bytes (e.g. if len(bitfield)%8 != 0: print 'Make sure the bitfield can be fully represented by bytes!') to ensure there is no ambiguity in how fields are manipulated in different programming languages, different libraries within programming languages, and different databases. In other words, the database, python, the library I'm going to recommend, etc. are all going to either store or be able to represent this bitarray in the form of a byte array. If the bitarray provided doesn't divide evenly into bytes, one of three things will happen:
1) An error will be raised, (this is optimistic)
2) The bitarray will be auto-magically left padded.
3) The bitarray will be auto-magically right padded.

I'd recommend using a bitstring library of some sort. I have used python-bitstring for this purpose. I didn't take the time to deal with ODBC here, but the idea is basically the same, and leverages srgerg's answer:

Examples:

#!/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

The output of this is:

                        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'

Note that since you don't have a bitstring that can be directly broken down into bytes (it's a string that represents 30 bits), the only way to get the exact same string was to specify a length, and even then the results were not consistent depending on how the BitArray was instantiated.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文