如何在Python中编写作为二进制的长整数?
在Python中,长整数具有无限精度。我想将一个16字节(128位)的整数写入文件<标准库中的code>struct最多只支持8字节整数<代码>数组具有相同的限制。有没有一种方法可以在不屏蔽和移动每个整数的情况下实现这一点如何在Python中编写作为二进制的长整数?,python,struct,biginteger,Python,Struct,Biginteger,在Python中,长整数具有无限精度。我想将一个16字节(128位)的整数写入文件struct最多只支持8字节整数数组具有相同的限制。有没有一种方法可以在不屏蔽和移动每个整数的情况下实现这一点 这里有一些澄清:我正在写入一个将从非Python程序读入的文件,所以pickle被删除了。所有128位都已使用。如果不想编写代码,可以将对象pickle为二进制,使用协议缓冲区(我不知道它们是否允许序列化无限制精度的整数)或BSON 但是编写一个通过移位来转储16字节整数的函数,如果不是时间关键的话,应该
这里有一些澄清:我正在写入一个将从非Python程序读入的文件,所以pickle被删除了。所有128位都已使用。如果不想编写代码,可以将对象pickle为二进制,使用协议缓冲区(我不知道它们是否允许序列化无限制精度的整数)或BSON
但是编写一个通过移位来转储16字节整数的函数,如果不是时间关键的话,应该不会那么困难。两种可能的解决方案:
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)打包这个字节列表,我认为对于无符号整数(并忽略endianness),类似于
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特定输出、不使用显式掩码和(我假设)不使用任何非标准模块的要求。不过并不特别优雅。该模块与内置的bin()
函数相结合,对于简单灵活的解决方案来说似乎是一个很好的组合
bytes = bitarray(bin(my_long)[2:]).tobytes()
endianness可以通过多行代码来控制。您必须评估效率。为什么不将struct与无符号long-long类型一起使用两次呢
import struct
some_file.write(struct.pack("QQ", var/(2**64), var%(2**64)))
这里记录了这一点(向下滚动以获得带有Q的表):这可能有点晚了,但我不明白为什么不能使用struct:
bigint = 0xFEDCBA9876543210FEDCBA9876543210L
print bigint,hex(bigint).upper()
cbi = struct.pack("!QQ",bigint&0xFFFFFFFFFFFFFFFF,(bigint>>64)&0xFFFFFFFFFFFFFFFF)
print len(cbi)
bigint本身被拒绝,但如果您使用&0xFFFFFFFFFFFFFFFF将其屏蔽,则可以将其减少为8字节的int而不是16字节的int。然后上半部分也被移动和遮罩。您可能需要稍微调整字节顺序。我用了这个!标记以告诉它生成网络端字节顺序。此外,可能需要反转msb和lsb(高位字节和低位字节)。我将把它作为一个练习留给用户来决定。我想说,将内容保存为网络端将更安全,这样您就可以始终知道数据的端
不,不要问我网络端是大端还是小端…在Python 3.2及更高版本中,您可以使用
int.to_bytes
和int.from_bytes
:基于@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)
这将正确处理负整数,并让用户设置字节数看起来他已经这样做了-标准库中的struct最多只支持8字节整数。您需要整个128位范围,还是只需要较低的64位,您需要有符号整数?可能是“无效”的重复?你能说得更具体一点,以便我能解决它吗?变量名(
n
vs.long\u int
)有些混乱。此外,您可能应该使用n/=256
或n>=8
或n,b=divmod(n,256)
而不是n/=256
,以防止Python3中出现(几乎)无限循环(或在传递浮点时)。@Apalala,@Sven Marnach。谢谢。如果使用long\u int,b=divmod(long\u int,256)
:)可能会更好看。这对于负输入失败:hex(x)
返回-0x123
例如。@Score\u下:第一句话是“对于无符号整数”。小心bin()
生成类似于0b0101110
的内容,因此您需要删除0b
前缀。您还需要tobytes()
而不是tostring()
。