如何将整数转换为十六进制并将其写入文件?

3

我希望在Python 2.7.13中完成以下操作:

  • 将int值转换为16进制(58829405413336430应变为d101085402656e
  • 向创建的16进制添加“payload”(简单字符串,如c1234)
  • 16进制写入文件

我的代码目前看起来是这样的:

mime=58829405413336430
payload="c9999"

fw_file=open('testhex', 'wb')
fw_file.write("%x" % mime)
fw_file.write(str(payload).encode("hex"))
fw_file.close()

我得到了以下文件(在Debian上使用xxd):

xxd HACKEDTOGETHER
00000000: 6431 3031 3038 3534 3032 3635 3665 3633  d101085402656e63
00000010: 3339 3339 3339 3339                      39393939

这不是我需要的。我需要一个看起来像这样的文件:
xxd WORKING
00000000: d101 0854 0265 6e63 3939 3939            ...T.enc9999

以下是我的理解:
“%x”%mime将我的int转换为十六进制,但它被写为字符串。 encode正确执行了此操作,但无法处理整数。我如何规避此行为并将“纯”十六进制写入文件?如果无法在Python 2中执行此操作,则可以使用Python 3。
作为我在StackOverflow上的第一个问题,请告诉我是否应该采取任何不同的做法。

十六进制仅是表示整数的一种方式,因此不是“转换”。 - Basile Starynkevitch
1个回答

2
问题的一部分在于,"%x" % mime 的结果是一个十六进制字符对(例如此处的 "d101085402656e"),它表示该格式下整数 mime 的值,因此这就是写入文件的内容。然而,需要的是组成整数本身的实际字节值。
在 Python 3 中,可以通过使用一个名为 to_bytes() 的内置方法来轻松解决此问题,该方法已添加到该版本的 int 类型中,但在 Python 2.x 中必须使用另一种方式。
由于您使用了str(payload).encode("hex"),这也会导致类似的问题,它返回的是十六进制字符串表示形式,而不是已经在payload中的每个字符的实际字节值,这正是所需的。幸运的是,在这种情况下,可以通过使用Python 2.x内置的bytearray类轻松完成需要的操作。
下面是我编写的一个函数版本,作为对相关questionanswer的一部分,可以处理mime值的问题。
在该函数定义之后的代码显示了如何在此情况下使用它,以及如何使用bytearray类将正确的二进制数据写入文件。
def int_to_bytes(n, minlen=0):
    """ Convert integer to bytearray with optional minimum length. 
    """
    if n > 0:
        arr = []
        while n:
            n, rem = n >> 8, n & 0xff
            arr.append(rem)
        b = bytearray(reversed(arr))
    elif n == 0:
        b = bytearray(b'\x00')
    else:
        raise ValueError('Only non-negative values supported')

    if minlen > 0 and len(b) < minlen: # zero padding needed?
        b = (minlen-len(b)) * '\x00' + b
    return b

mime = 58829405413336430
payload = 'c9999'

with open('testhex', 'wb') as fw_file:
    fw_file.write(int_to_bytes(mime))
    fw_file.write(bytearray(payload))

这是一个十六进制转储,显示了由Python 2.7.15生成的testhex文件的内容:
00000000h: D1 01 08 54 02 65 6E 63 39 39 39 39             ; Ñ..T.enc9999

我认为他们不希望负载转换为ASCII十六进制。您可以使用“n >> 8,n&0xff”替换“divmod(n,256)”。 - Mark Ransom
@Mark:感谢你提醒负载问题。我已经相应地更新了我的答案,但我保留了divmod(),因为虽然你说的听起来很合理,但是一段时间前我实际测试了一下,令人惊讶的是它更快。 - martineau
我刚在3.6中计时,得到了相反的结果:divmod是0.13,而>> &是0.10。 - Mark Ransom
@Mark:不能反驳那个......回答进一步更新。再次感谢您的见解。我认为我混淆了对divmod()使用和另一个内置函数(math.hypot()在这里不相关)的使用。 - martineau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接