【问题标题】:How to open and present raw binary data in Python?如何在 Python 中打开和呈现原始二进制数据?
【发布时间】:2015-10-15 09:52:55
【问题描述】:

这似乎是应该有很多重复和大量答案的问题类型,但我的搜索结果只是令人沮丧,没有可用的解决方案。

在 Python(最好是 3.x)中,我想知道如何打开任意类型的文件,读取存储在磁盘上的字节,并以最“原生”、“原始”的形式呈现这些字节', '原始' 形式,在对它们进行任何编码之前。

如果文件作为00010100 10000100 ... 的流存储在磁盘上,那么这就是我希望在屏幕上呈现的内容。

这类问题通常会引发“您为什么想知道”和“用例是什么”的回答。我很好奇,这是我的用例。

在将其标记为重复之前,请确保您想到的答案确实回答了问题(而不仅仅是讨论编码等)。谢谢!

在前三个答案后编辑:

感谢到目前为止的三位响应者,尤其感谢 J.F. Sebastian 的扩展讨论。从所说的看来,我的问题归结为文件中的字节如何物理记录到磁盘以及如何读取和呈现它们。在这一点上,在 Python 中似乎不可能以原始形式获得字节的视图,但它们有多种表示形式。整数、十六进制值、ascii 等。由于问题尚未解决,我将把问题留待更多输入。

【问题讨论】:

  • 正如我在回答中明确所说:Python 确实获得了原始字节:您可以读取它们,也可以编写它们。如果你的问题是如果你打电话给file.read(1) 到底发生了什么,那么这是一个不同的问题(答案是:很多事情正在发生——不同的操作系统表现不同,不同的文件系统表现不同,硬盘也是整台计算机,即,你的普通电脑就是电脑的网络——只要不影响结果——没关系)。

标签: python python-3.x binary-data


【解决方案1】:

如果你对字节没问题:

with open('yourfile', 'rb') as fobj:
    raw_bytes = fobj.read()
    print(raw_bytes)

如果你真的想要二进制:

with open('yourfile', 'rb') as fobj:
    raw_bytes = fobj.read()
    print(' '.join(map(lambda x: '{:08b}'.format(x), raw_bytes)))

【讨论】:

    【解决方案2】:

    'rb' 模式使您可以从 Python 文件中读取原始二进制数据:

    with open(filename, 'rb') as file:
        raw_binary_data = file.read()
    

    type(raw_binary_data) == bytesbytes 是 Python 中不可变的字节序列。

    不要混淆字节和它们的文本表示:print(raw_binary_data) 会显示数据的文本表示,例如,一个字节 127(以 10 为底:十进制),您可以表示为
    bin(127) == '0b1111111'(基数 2:二进制)或 hex(127) == '0x7f'(基数 16:十六进制)显示为 b'\x7f'(打印七个 ascii 字符)。可打印 ascii 范围内的字节表示为相应的 ascii 字符,例如,b'\x41' 显示为 b'A' (65 == 0x41 == 0b1000001)。

    0x7f 字节不作为七个 ascii 二进制数字 1111111 存储在磁盘上,它不存储为两个 ascii 十六进制数字:7F,它不存储为三个文字十进制数字 127b'\x7f' 是字节的文本表示形式,可用于在 Python 源代码中指定它(您也不会在磁盘上找到文字的七个 ascii 字符 b'\x7f')。 此代码将一个单个字节写入磁盘:

    with open('output.bin', 'wb') as file:
        file.write(b'\x7f')
    

    必须使用某种字符来表示字节,它们是什么?

    操作系统接口(访问磁盘等硬件的方式)以字节为单位定义,例如POSIX read(2),即字节是这里的基本单位:您可以直接读取/写入字节——您不需要任何中间表示。观看Richard Feynman. Why.

    字节的表示方式物理上在操作系统驱动程序和硬件之间——它可能是任何东西——你不必担心它:它隐藏在统一的操作系统接口后面。见How is data physically written, read and stored inside hard drives?

    您可以在 Python 中直接调用os.read(),但您不需要它; file.read() 为您完成(Python 3 文件对象直接在 POSIX 接口之上实现。Python 2 I/O 使用 C stdio 库,而后者又使用 OS 接口来实现其功能)。

    正如您所指出的,由操作系统驱动程序和硬件来确定字节的写入方式,但 Python 解释器将能够读取它们。所以它在读一些东西——那是什么?它不是在读取磁盘上粒子的磁性方向,是吗?它正在读取一些象征性的东西,我想访问它。

    它正在读取字节。硬盘是一台小型计算机,因此interesting things 可能会发生,但它不会改变它一直是字节(就“符号”或软件而言)。

    The book "CODE The Hidden Language of Computer Hardware and Software" 非常温和地介绍了信息在计算机中的表示方式——直到第 180 页才定义了“字节”这个词。要了解计算机中使用的抽象级别,the course "From NAND to Tetris" can help

    【讨论】:

    • @DhaLee: 你明白00000001八个 字符,你可以解释 为base 2 系统中的一个数字(0b1(base 2) == 0x1 (base 16) == 1 (base 10) ) 因此它可以表示 b'\x01' 字节?你知道同一个数字可以用不同的基数来表示吗?您是否知道您不能在一个字节中寻址单个位:根据定义,一个字节是最小的可寻址单元?一些计算机在一个字节中可能有更多/少于 8 位,尽管在这里无关紧要。
    • @DhaLee:没有。字节在这里是基本的(这不是 Python 的限制)。观看the video that I've linked。这可能有助于理解为什么字节不以其他方式表示。
    【解决方案3】:

    Python 3 将文件数据表示为bytes。该类型基本上是从 0 到 255 的整数列表,因此是字节列表。它们有一些方便的方法(例如解码为字符串),并且在打印时呈现类似于字符串。

    要逐位表示,打开文件时应使用b模式。

    bin() 将帮助您将整数转换为二进制表示。但您可能需要去掉前两个字符并填写 0s。

    with open(filename, 'rb') as my_file:
        my_bytes = my_file.read()
        bin_list = [bin(i)[2:].rjust(8, '0') for i in my_bytes]
        print(' '.join(bin_list))
    

    【讨论】:

    • 只需将其转换为列表:list(b'abc')[97, 98, 99]。您还可以通过索引b'abc'[1]98 访问每个元素。
    【解决方案4】:

    浏览了一些文档后,看起来 Python 并没有提供直接操作其数据的物理存储的接口。

    相反,数据存储的处理被传递给操作系统。这没有明确说明,但我从它的io module 文档中得到了印象。

    如果您有一个存储为0110100001100101011011000110110001101111 的文件,并且您使用open() 打开它。 Python 将通过与您的操作系统交互来获取其信息,并最终返回一个bytes 对象,您可以通过该对象以不同的格式查看其内容(例如带有b 前缀或十六进制的文本字符串)。

    但是,以这种方式实际存储二进制文件(即纯二进制01)是很棘手的,因为大多数程序不支持它。大多数时候,他们使用间接方式:您指定内容的表示形式,或者使用编码为\x68\x65\x6c\x6c\x6f,或者b'hello',然后程序和您的操作系统完成繁重的工作并将其放回@ 987654330@.

    如果我错了,请纠正我:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-30
      • 1970-01-01
      • 2018-09-15
      • 1970-01-01
      • 2016-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多