【问题标题】:Python binary EOFPython二进制EOF
【发布时间】:2014-10-17 09:59:07
【问题描述】:

我想读取一个二进制文件。 谷歌搜索“python binary eof”引导我here

现在,问题:

  1. 为什么容器(SO 答案中的 x)不包含单个(当前)字节,而是包含一大堆?我做错了什么?
  2. 如果应该是这样并且我没有做错任何事情,那么如何读取单个字节?我的意思是,在使用read(1) 方法读取文件时,有什么方法可以检测 EOF?

【问题讨论】:

  • 我不知道为什么我不能无害地从社区获得一点帮助?为什么那些不值得 5 页答案、维基页面或在光荣的名人堂中为伟大人物提供一席之地的问题总是会被否决?为什么我应该只问火箭科学?
  • 如果您对此处所提出的问题的看法不满意,请在 not 中发表评论,因为投反对票的人很久以前就已经放弃了适当的反应 - 并且不会t 可能阅读该评论。但其他人会。如果您真的不同意并且绝对确定您的问题已经到达quality standard expected,您可以在meta 上提出您的问题。但是在这样做之前be prepared

标签: python binary eof


【解决方案1】:

逐字节读取:

with open(filename, 'rb') as f:
    while True:
        b = f.read(1)
        if not b:
            # eof
            break
        do_something(b)

【讨论】:

  • 但是如果你的文件包含一个零字节,这将在文件被完全读取之前提前结束
  • @slashdottir:错误。 not '\0'False。只有not ''True
【解决方案2】:

"" 表示文件结束

with open(filename, 'rb') as f:
    for ch in iter(lambda: f.read(1),""): # keep calling f.read(1) until end of the data
        print ch

【讨论】:

    【解决方案3】:

    引用documentation

    file.read([size])

    最多从文件中读取 size 字节(如果读取达到 EOF 则更少在获取 size 字节之前)。如果 size 参数为负数或省略,则读取所有数据,直到达到 EOF。字节作为字符串对象返回。 当立即遇到 EOF 时返回一个空字符串。 (对于某些文件,如 ttys,在 EOF 被命中后继续读取是有意义的。)请注意,此方法可能会多次调用底层 C 函数 fread() 以获取尽可能接近 size 的字节。另请注意,在非阻塞模式下,即使没有给出大小参数,返回的数据也可能少于请求的数据。

    这意味着(对于regular file):

    • f.read(1) 将返回一个字节对象,其中包含 1 字节或 0 字节是否达到 EOF
    • f.read(2) 将返回一个包含 2 个字节的字节对象,如果在第一个字节之后到达 EOF,则返回 1 个字节,如果立即遇到 EOF,则返回 0 个字节。
    • ...

    如果您想一次读取一个字节的文件,则必须在循环中 read(1) 并测试结果的“空性”:

    # From answer by @Daniel
    with open(filename, 'rb') as f:
        while True:
            b = f.read(1)
            if not b:
                # eof
                break
            do_something(b)
    

    如果您想一次读取 50 个字节的“块”文件,则必须循环使用 read(50)

    with open(filename, 'rb') as f:
        while True:
            b = f.read(50)
            if not b:
                # eof
                break
            do_something(b) # <- be prepared to handle a last chunk of length < 50
                            #    if the file length *is not* a multiple of 50
    

    事实上,您甚至可以更快地中断一次迭代:

    with open(filename, 'rb') as f:
        while True:
            b = f.read(50)
            do_something(b) # <- be prepared to handle a last chunk of size 0
                            #    if the file length *is* a multiple of 50
                            #    (incl. 0 byte-length file!)
                            #    and be prepared to handle a last chunk of length < 50
                            #    if the file length *is not* a multiple of 50
            if len(b) < 50:
                break
    

    关于你问题的另一部分:

    为什么容器 [..] 包含 [..] 一大堆 [bytes]?

    参考that code

    for x in file:  
       i=i+1  
       print(x)  
    

    再次引用the doc

    文件对象是它自己的迭代器,[..]。当文件用作迭代器时,通常在 for 循环中(例如,for line in f: print line.strip()),next() 方法会被重复调用。此方法返回下一个输入行,或在打开文件以进行读取时遇到 EOF 时引发 StopIteration(打开文件以进行写入时行为未定义)。

    上面的代码逐行读取一个二进制文件。即在每次出现 EOL 字符 (\n) 时停止。通常,这会导致不同长度的块,因为大多数二进制文件都包含随机分布的字符。

    我不鼓励您以这种方式读取二进制文件。请选择基于read(size) 的解决方案。

    【讨论】:

    • 有很多接近这个的答案是行不通的!感谢您发布一个伟大而详细的答案!!!没有这个答案,我无法完成我的项目!
    • 对于 f.read(1) 示例:如果您的字节流中的字节为零,那么测试会在您完成读取文件之前提前退出
    • @slashdottir 在 Python 中,只有 empty 序列是 False (docs.python.org/3.1/library/stdtypes.html) 而不是 False 的就是 True。因此,如果您的字节字符串包含 \x00,则它 not 为空,因此 b"\x00" 为 True。您可以在 REPL 中进行测试:"T" if b"\x00" else "F"
    • 这里是明智的,重要的是要了解缓冲文件时的幕后情况。实际上有几个缓冲区对象正在创建,其中包含缓冲文件的一部分。见here。 Python 应该使这种情况不太可能发生,但由此引发的经典问题是,当完成时,您最终会发现部分文件仍位于这些底层缓冲区对象之一中。如果您缺少数据,请务必刷新它们。
    • 我不喜欢 break 语句。它使 while 的谓词在退出时为 false 的保证无效。
    【解决方案4】:

    这就是我所做的。对read 的调用在遇到文件末尾时返回一个假值,这将终止循环。使用while ch != "": 复制了图像,但它给了我一个挂起的循环。

    from sys import argv
    donor = argv[1]
    recipient = argv[2]
    # read from donor and write into recipient
    # with statement ends, file gets closed
    with open(donor, "rb") as fp_in:
        with open(recipient, "wb") as fp_out:
            ch = fp_in.read(1)
            while ch:
                fp_out.write(ch)
                ch = fp_in.read(1)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-19
      • 2014-01-24
      • 2017-09-04
      • 2011-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多