How do I write a long integer as binary in Python?
在python中,长整数具有无限的精度。我想写一个16字节(128位)的整数到一个文件。标准库中的
这里有一些说明:我正在写一个将从非python程序中读取的文件,所以pickle已经不在了。所有128位都被使用。
我认为对于无符号整数(忽略了endianness),类似于
1 2 3 4 5 6 7 8 9 10 11 12 | import binascii def binify(x): h = hex(x)[2:].rstrip('L') return binascii.unhexlify('0'*(32-len(h))+h) >>> for i in 0, 1, 2**128-1: ... print i, repr(binify(i)) ... 0 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' 1 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' 340282366920938463463374607431768211455 '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' |
技术上可以满足具有非特定于Python的输出、不使用显式掩码和(我假设)不使用任何非标准模块的要求。不过不是特别优雅。
两种可能的解决方案:
只需泡菜你的长整数。这将以一种特殊的格式写入整数,如果这是您所希望的,则可以再次读取它。
使用此答案中的第二个代码段将long int转换为big endian字符串(如果愿意,可以很容易地将其更改为little endian),然后将此字符串写入文件。
问题是bigints的内部表示不直接包括您请求的二进制数据。
pypi位数组模块与内置的
1 | bytes = bitarray(bin(my_long)[2:]).tobytes() |
可以用更多的代码行来控制endianness。你得评估一下效率。
为什么不将struct与无符号长整型一起使用两次?
1 2 | import struct some_file.write(struct.pack("QQ", var/(2**64), var%(2**64))) |
这里记录了这一点(向下滚动以获得带有q的表):http://docs.python.org/library/struct.html
使用python 3.2及更高版本,您可以使用
这可能无法避免"屏蔽并移动每个整数"的要求。我不确定在python long值的上下文中,避免使用mask和shift意味着什么。
字节如下:
1 2 3 4 5 6 7 | def bytes( long_int ): bytes = [] while long_int != 0: b = long_int%256 bytes.insert( 0, b ) long_int //= 256 return bytes |
然后您可以使用
可能有点晚了,但我不明白为什么不能使用struct:
1 2 3 4 5 6 | bigint = 0xFEDCBA9876543210FEDCBA9876543210L print bigint,hex(bigint).upper() cbi = struct.pack("!QQ",bigint&0xFFFFFFFFFFFFFFFF,(bigint>>64)&0xFFFFFFFFFFFFFFFF) print len(cbi) |
bigint本身被拒绝,但是如果您用&0xffffffffffffffffffffffff屏蔽它,您可以将它减少到8字节int而不是16字节。然后上半部分也被移动和遮蔽。您可能需要对字节排序进行一些操作。我用过了!标记以告诉它生成网络结束字节顺序。此外,可能需要反转MSB和LSB(上下字节)。我将把它作为练习留给用户来决定。我想说,将数据保存为network endian会更安全,所以您总是知道数据的endian是什么。
不,不要问我network endian是大还是小…
您可以将对象pickle为二进制,使用协议缓冲区(我不知道它们是否允许您序列化无限精度整数),或者如果不想编写代码,使用bson。
但是写一个通过移动来转储16字节整数的函数,如果它不是时间临界的,就不那么难了。