在Python中,长整数具有无限精度。我想写一个16字节(128位)整数到一个文件。标准库中的struct
仅支持最多8个字节的整数。 array
具有相同的限制。有没有办法在没有屏蔽和移动每个整数的情况下做到这一点?
这里有一些澄清:我正在写一个将从非Python程序读入的文件,因此pickle已经出局了。使用全部128位。
答案 0 :(得分:8)
我认为对于无符号整数(并忽略字节序),如
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特定输出的要求,而不是使用显式掩码,并且(我假设)不使用任何非标准模块。但不是特别优雅。
答案 1 :(得分:5)
两种可能的解决方案:
只需pickle您的长整数。这将以特殊格式写入整数,这样就可以再次读取它,如果你想要的话。
使用this answer中的第二个代码片段将long int转换为大端字符串(如果您愿意,可以将其轻松更改为小端),并将此字符串写入您的文件。 / p>
问题是bigints的内部表示不直接包含您要求的二进制数据。
答案 2 :(得分:3)
PyPi bitarray模块与内置bin()
功能相结合,似乎是一个简单灵活的解决方案的良好组合。
bytes = bitarray(bin(my_long)[2:]).tobytes()
可以使用更多代码行来控制字节序。你必须评估效率。
答案 3 :(得分:2)
为什么不两次使用 unsigned long long 类型的struct?
import struct
some_file.write(struct.pack("QQ", var/(2**64), var%(2**64)))
这里有记录(向下滚动以获得Q表):http://docs.python.org/library/struct.html
答案 4 :(得分:1)
这可能无法避免“屏蔽并移动每个整数”的要求。我不确定在Python长值的上下文中避免使用掩码和移位意味着什么。
字节是这些:
def bytes( long_int ):
bytes = []
while long_int != 0:
b = long_int%256
bytes.insert( 0, b )
long_int //= 256
return bytes
然后,您可以使用struct.pack( '16b', bytes )
答案 5 :(得分:1)
使用Python 3.2及更高版本,您可以使用int.to_bytes
和int.from_bytes
:https://docs.python.org/3/library/stdtypes.html#int.to_bytes
答案 6 :(得分:0)
您可以将对象pickle为二进制,使用协议缓冲区(我不知道它们是否允许您序列化无限精度整数)或BSON(如果您不想编写代码)。
但是,如果它不是时间关键的话,编写一个通过移位来转储16字节整数的函数应该不那么难。
答案 7 :(得分:0)
这可能有点晚了,但我不明白为什么你不能使用struct:
bigint = 0xFEDCBA9876543210FEDCBA9876543210L
print bigint,hex(bigint).upper()
cbi = struct.pack("!QQ",bigint&0xFFFFFFFFFFFFFFFF,(bigint>>64)&0xFFFFFFFFFFFFFFFF)
print len(cbi)
bigint本身被拒绝,但是如果用& 0xFFFFFFFFFFFFFFFF掩盖它,你可以将它减少到8字节而不是16字节。然后上部移位并屏蔽。您可能需要稍微使用字节排序。我用了!标记告诉它产生网络字节序字节顺序。此外,可能需要反转msb和lsb(上部和下部字节)。我将把它作为练习让用户确定。我会说保存东西,因为网络端将更安全,所以你总是知道你的数据的结束是什么。
不,不要问我网络端是大还是小端......
答案 8 :(得分:0)
基于@DSM的答案,并且为了支持负整数和变化的字节大小,我创建了以下改进的代码段:
def to_bytes(num, size):
x = num if num >= 0 else 256**size + num
h = hex(x)[2:].rstrip("L")
return binascii.unhexlify("0"*((2*size)-len(h))+h)
这将正确处理负整数,并让用户设置字节数