【问题标题】:How to read binary files as hex in Python?如何在 Python 中将二进制文件读取为十六进制?
【发布时间】:2016-01-08 23:01:34
【问题描述】:

我想读取一个包含数据的文件,以十六进制格式编码:

01ff0aa121221aff110120...etc

文件包含 >100.000 个这样的字节,有些超过 1.000.000(它们来自 DNA 测序)

我尝试了以下代码(和其他类似代码):

filele=1234563
f=open('data.geno','r')
c=[]
for i in range(filele):
  a=f.read(1)
  b=a.encode("hex")
  c.append(b)
f.close()

这给每个字节单独的“aa”“01”“f1”等,这对我来说是完美的!

直到(在这种情况下)字节 905 恰好是“1a”为止,这都可以正常工作。我还尝试了同样在同一字节处停止的 ord() 函数。

可能有一个简单的解决方案?

【问题讨论】:

  • 当你说它停止时,你是否得到了异常,还是什么?另外要明确的是,这是一个二进制文件,您希望将其作为十六进制编码的字节值序列读取?
  • 如果您正在读取二进制文件,最好使用'rb' 作为open 的标志。
  • 假设您准确地呈现代码,我想不出任何失败的原因。每个离散字节值(以及与此相关的空字符串)都编码为十六进制对我来说很好(在 Py2 中,hex 编解码器已从 Py3 中的str.encode 中删除)。自己尝试每个可能的字符:for c in map(chr, range(256)): print c.encode('hex')。他们都工作。我的答案优化了在 C 层完成大部分工作(以换取稍微更高的峰值内存使用率),但是您给出的代码不能以任何有意义的方式中断。请给出确切的例外或不当行为。

标签: python python-2.7


【解决方案1】:

简单的解决方案是binascii:

import binascii

# Open in binary mode (so you don't read two byte line endings on Windows as one byte)
# and use with statement (always do this to avoid leaked file descriptors, unflushed files)
with open('data.geno', 'rb') as f:
    # Slurp the whole file and efficiently convert it to hex all at once
    hexdata = binascii.hexlify(f.read())

这只是给你一个十六进制值的str,但它比你想要做的要快得多。如果你真的想为每个字节提供一堆长度为 2 的十六进制字符串,你可以轻松地转换结果:

hexlist = map(''.join, zip(hexdata[::2], hexdata[1::2]))

这将产生与每个字节的十六进制编码相对应的 len 2 strs 列表。为避免 hexdata 的临时副本,您可以使用类似但不太直观的方法,通过使用相同的迭代器两次与 zip 来避免切片:

hexlist = map(''.join, zip(*[iter(hexdata)]*2))

更新:

对于 Python 3.5 及更高版本的用户,bytes objects spawned a .hex() method,因此无需任何模块即可将原始二进制数据转换为 ASCII 十六进制。顶部的代码块可以简化为:

with open('data.geno', 'rb') as f:
    hexdata = f.read().hex()

【讨论】:

    【解决方案2】:

    只是对这些的附加说明,请确保在文件的 .read 中添加一个中断,否则它将继续运行。

    def HexView():
        with open(<yourfilehere>, 'rb') as in_file:
            while True:
                hexdata = in_file.read(16).hex()     # I like to read 16 bytes in then new line it.
                if len(hexdata) == 0:                # breaks loop once no more binary data is read
                    break
                print(hexdata.upper())               # I also like it all in caps. 
    

    【讨论】:

      【解决方案3】:

      如果文件以十六进制格式编码,每个字节不应该由 2 个字符表示吗?所以

      c=[]
      with open('data.geno','rb') as f:
          b = f.read(2)
          while b:
              c.append(b.decode('hex'))
              b=f.read(2)
      

      【讨论】:

      • 问题的语法不明确,开头的句子也可能意味着“我想读取数据并将其编码为十六进制”。问题的其余部分表明他们想要两个字符串,这有利于这种解释。我承认这很令人困惑。
      • 我以同样的方式提出了这个问题。 +1
      【解决方案4】:

      感谢所有有趣的答案!

      立即起作用的简单解决方案是将“r”更改为“rb”, 所以:

      f=open('data.geno','r')  # don't work
      f=open('data.geno','rb')  # works fine
      

      本例的代码实际上只有两个二进制位,所以一个字节包含四个数据,二进制; 00、01、10、11。

      你的!

      【讨论】:

        猜你喜欢
        • 2020-10-25
        • 1970-01-01
        • 1970-01-01
        • 2012-03-26
        • 2012-08-20
        • 2014-02-13
        • 2022-01-17
        • 2013-07-01
        • 1970-01-01
        相关资源
        最近更新 更多