【问题标题】:What is the perfect counterpart in Python for "while not EOF"Python中“虽然不是EOF”的完美对应物是什么
【发布时间】:2013-03-14 00:56:07
【问题描述】:

要读取一些文本文件,在 C 或 Pascal 中,我总是使用以下 sn-ps 来读取数据,直到 EOF:

while not eof do begin
  readline(a);
  do_something;
end;

因此,我想知道如何在 Python 中简单快速地做到这一点?

【问题讨论】:

    标签: python file iteration eof


    【解决方案1】:

    你可以模仿 Python 中的 C 习语。

    要读取最多 max_size 字节数的缓冲区,您可以这样做:

    with open(filename, 'rb') as f:
        while True:
            buf = f.read(max_size)
            if not buf:
                break
            process(buf)
    

    或者,一行一行的文本文件:

    # warning -- not idiomatic Python! See below...
    with open(filename, 'rb') as f:
        while True:
            line = f.readline()
            if not line:
                break
            process(line)
    

    您需要使用while True / break 构造,因为Python 中除了缺少从读取返回的字节之外还有no eof test

    在 C 中,您可能有:

    while ((ch != '\n') && (ch != EOF)) {
       // read the next ch and add to a buffer
       // ..
    }
    

    但是,您不能在 Python 中使用它:

     while (line = f.readline()):
         # syntax error
    

    因为assignments are not allowed in expressions 在 Python 中(尽管最新版本的 Python 可以使用赋值表达式来模仿这一点,见下文)。

    在 Python 中这样做肯定是更多惯用的:

    # THIS IS IDIOMATIC Python. Do this:
    with open('somefile') as f:
        for line in f:
            process(line)
    

    更新:从 Python 3.8 开始你也可以使用assignment expressions

     while line := f.readline():
         process(line)
    

    即使读取的行是空白的并且一直持续到 EOF,它仍然有效。

    【讨论】:

    • @MartijnPieters:现在可以了 :-)
    • 作为一名 C 和 Perl 程序员,您提出的 assignments are not allowed in expressions 对我来说至关重要。
    • "while True:" 方法在每次迭代需要对多个输入行进行操作时也很有用,这是惯用的 Python 所不允许的(据我所知,无论如何)。
    • 如果您不对文件做出假设,则不应阅读行。一个二进制文件可能有很多行……
    • 似乎非惯用的readline() 方式有一个优势:您可以进行细粒度的错误处理,例如捕获UnicodeDecodeError,而惯用的@987654335 则无法做到这一点@迭代。
    【解决方案2】:

    这个怎么样!让它变得简单!

    for line in open('myfile.txt', 'r'):
        print(line)
    

    无需浪费额外的行。并且不需要使用with关键字,因为当没有文件对象的引用时文件会自动关闭。

    【讨论】:

      【解决方案3】:

      除了@dawg 的出色答案之外,使用海象运算符(Python >= 3.8)的等效解决方案:

      with open(filename, 'rb') as f:
          while buf := f.read(max_size):
              process(buf)
      

      【讨论】:

        【解决方案4】:

        遍历文件以读取行:

        with open('somefile') as openfileobject:
            for line in openfileobject:
                do_something()
        

        文件对象是可迭代的,并且在 EOF 之前产生行。将文件对象用作可迭代对象使用缓冲区来确保高性能读取。

        你可以对标准输入做同样的事情(不需要使用raw_input():

        import sys
        
        for line in sys.stdin:
            do_something()
        

        为了完成图片,可以使用以下方式进行二进制读取:

        from functools import partial
        
        with open('somefile', 'rb') as openfileobject:
            for chunk in iter(partial(openfileobject.read, 1024), b''):
                do_something()
        

        其中chunk 一次最多可包含文件中的 1024 个字节,当openfileobject.read(1024) 开始返回空字节字符串时,迭代停止。

        【讨论】:

        • 注意:line 末尾会有一个换行符。
        • 读取行对于通用二进制文件来说有点危险,因为也许你有一个 6GiB 长的行……
        • @LtWorf:这就是为什么我展示了如何以块而不是行来读取二进制文件。
        • 我正在从一个正在运行的进程中读取stdin...所以在我终止进程之前它永远不会有 EOF。但是后来我到达“到现在为止”并且我陷入僵局。我如何检测到这一点而不是死锁?就像没有新行一样,停止读取文件(即使没有 EOF,在我的情况下它永远不会存在)。
        • @CharlieParker:如果你遇到了死锁,那么可能忘记了刷新缓冲区。如果没有实际的 MCVE,很难说更多。
        【解决方案5】:

        虽然上面有“以 python 方式做”的建议,但如果一个人想要真正拥有基于 EOF 的逻辑,那么我想使用异常处理是一种方法——

        try:
            line = raw_input()
            ... whatever needs to be done incase of no EOF ...
        except EOFError:
            ... whatever needs to be done incase of EOF ...
        

        例子:

        $ echo test | python -c "while True: print raw_input()"
        test
        Traceback (most recent call last):
          File "<string>", line 1, in <module> 
        EOFError: EOF when reading a line
        

        或在raw_input() 提示符下按 Ctrl-Z(Windows、Ctrl-Z Linux)

        【讨论】:

        • @TessellatingHeckler 这不是 the documentation 所说的:“当内置函数之一(input() 或 raw_input())遇到文件结束条件 (EOF) 时引发无需读取任何数据。”
        • @TadhgMcDonald-Jensen 好吧,它会的。多么奇怪。撤回虚假声明并删除不公平的反对票。
        【解决方案6】:

        你可以使用下面的代码sn-p。 readlines() 一次读取整个文件并按行拆分。

        line = obj.readlines()
        

        【讨论】:

          【解决方案7】:

          您可以使用下面的代码 sn-p 逐行读取,直到文件末尾

          line = obj.readline()
          while(line != ''):
          
              # Do Something
          
              line = obj.readline()
          

          【讨论】:

          • IMO,这是最能反映所问内容的一个答案。
          • 经常迭代行会扭曲程序的结构。例如,在语言解析器中,您希望读取行并按顺序处理它们。您不想仅仅为了循环读取行然后将它们发送到解析器而重构顶层。
          【解决方案8】:

          打开文件并逐行读取的 Python 习惯用法是:

          with open('filename') as f:
              for line in f:
                  do_something(line)
          

          文件将在上述代码结束时自动关闭(with 结构负责处理)。

          最后,值得注意的是line 将保留尾随的换行符。这可以使用以下方法轻松删除:

          line = line.rstrip()
          

          【讨论】:

          • +1,还向 OP 指出这与非常相似的for line in f.readlines(): ...(通常建议的解决方案)相同。
          猜你喜欢
          • 2022-01-20
          • 2017-11-12
          • 2019-05-27
          • 2019-09-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多