Was ist das perfekte Gegenstück in Python für "während nicht EOF"


114

Um eine Textdatei in C oder Pascal zu lesen, verwende ich immer die folgenden Schnipsel, um die Daten bis EOF zu lesen:

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

Daher frage ich mich, wie ich dies in Python einfach und schnell tun kann.

Antworten:


189

Durchlaufen Sie die Datei, um Zeilen zu lesen:

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

Dateiobjekte sind iterierbar und ergeben bis EOF Linien. Wenn Sie das Dateiobjekt als iterable verwenden, wird ein Puffer verwendet, um performante Lesevorgänge sicherzustellen.

Sie können dasselbe mit dem stdin tun (keine Verwendung erforderlich raw_input():

import sys

for line in sys.stdin:
    do_something()

Um das Bild zu vervollständigen, können binäre Lesevorgänge durchgeführt werden mit:

from functools import partial

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

Dabei chunkenthält die Datei bis zu 1024 Byte gleichzeitig. Die Iteration wird beendet, wenn openfileobject.read(1024)leere Byte-Zeichenfolgen zurückgegeben werden.


4
Hinweis: Am Ende linewird ein neues Zeilenzeichen angezeigt.
ben_joseph

1
Das Lesen von Zeilen ist für generische Binärdateien etwas gefährlich, da Sie möglicherweise eine 6 GB lange Zeile haben…
LtWorf

@LtWorf: Deshalb zeige ich, wie man Binärdateien in Blöcken anstatt in Zeilen liest .
Martijn Pieters

Ich lese aus einem stdinlaufenden Prozess ... also hat es nie EOF, bis ich den Prozess beendet habe. Aber dann erreiche ich das "Ende bis jetzt" und bin festgefahren. Wie erkenne ich das und keinen Deadlock? Wenn keine neuen Zeilen vorhanden sind, hören Sie auf, die Dateien zu lesen (auch wenn kein EOF vorhanden ist, der in meinem Fall niemals vorhanden sein wird).
Charlie Parker

@CharlieParker: Wenn Sie einen Deadlock erreicht haben, vergisst wahrscheinlich etwas , einen Puffer zu leeren . Ohne eine tatsächliche MCVE ist es schwer, mehr als das zu sagen.
Martijn Pieters

61

Sie können das C-Idiom in Python imitieren.

So lesen Sie einen Puffer bis zu einer max_sizeAnzahl von Bytes:

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

Oder eine Textdatei Zeile für Zeile:

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

Sie müssen while True / breakKonstrukt verwenden, da es in Python keinen anderen Eof-Test gibt als das Fehlen von Bytes, die von einem Lesevorgang zurückgegeben werden.

In C haben Sie möglicherweise:

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

In Python ist dies jedoch nicht möglich:

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

da Zuweisungen in Ausdrücken in Python nicht zulässig sind (obwohl neuere Versionen von Python dies mithilfe von Zuweisungsausdrücken nachahmen können, siehe unten).

Es ist sicherlich mehr idiomatische in Python zu tun:

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

Update: Seit Python 3.8 können Sie auch Zuweisungsausdrücke verwenden :

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

@ MartinijnPieters: Jetzt tut es :-)
dawg

3
Als C- und Perl-Programmierer war es für mich von entscheidender Bedeutung, dass Zuweisungen in Ausdrücken nicht zulässig sind .
CODE-REaD

1
Die Methode "while True:" ist auch nützlich, wenn Sie mehr als eine Eingabezeile pro Iteration bearbeiten müssen, was der idiomatische Python nicht zulässt (soweit ich das beurteilen kann).
Donald Smith

Sie sollten keine Zeilen lesen, wenn Sie keine Annahmen in der Datei treffen. Eine Binärdatei könnte große Zeilen haben ...
LtWorf

Es scheint, dass die nicht-idiomatische readline()Methode einen Vorteil hat : Sie können eine feinkörnige Fehlerbehandlung wie das Fangen durchführen UnicodeDecodeError, was Sie mit der idiomatischen forIteration nicht tun können .
flow2k

17

Die Python-Sprache zum Öffnen und zeilenweisen Lesen einer Datei lautet:

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

Die Datei wird am Ende des obigen Codes automatisch geschlossen (das withKonstrukt kümmert sich darum).

Schließlich ist anzumerken, dass linedie nachfolgende Newline erhalten bleibt. Dies kann leicht entfernt werden mit:

line = line.rstrip()

1
+1 und weist das OP auch darauf hin, dass dies nicht dasselbe ist wie die sehr ähnliche for line in f.readlines(): ..., häufig vorgeschlagene Lösung.
jedwards

12

Sie können das folgende Codefragment verwenden, um Zeile für Zeile bis zum Ende der Datei zu lesen

line = obj.readline()
while(line != ''):

    # Do Something

    line = obj.readline()

1
IMO, dies ist die einzige Antwort, die am besten widerspiegelt, was gefragt wurde.
Gvrocha

Oft würde das Durchlaufen der Zeilen die Struktur des Programms verzerren. In einem Sprachparser möchten Sie beispielsweise die Zeilen lesen und nacheinander verarbeiten. Sie möchten die oberste Ebene nicht neu strukturieren, nur um Lesezeilen zu schleifen und sie dann an den Parser zu senden.
Jonathan Starr

11

Zwar gibt es oben Vorschläge für "Python-Methode", aber wenn man wirklich eine auf EOF basierende Logik haben möchte, dann ist die Verwendung der Ausnahmebehandlung vermutlich die richtige Methode -

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

Beispiel:

$ 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

Oder drücken Sie Ctrl-Zan einer raw_input()Eingabeaufforderung (Windows, Ctrl-ZLinux)


@TessellatingHeckler Das ist nicht das, was in der Dokumentation steht: " Wird ausgelöst, wenn eine der integrierten Funktionen (input () oder raw_input ()) eine Dateiende-Bedingung (EOF) erreicht, ohne Daten zu lesen."
Tadhg McDonald-Jensen

1
@ TadhgMcDonald-Jensen Na hey, so wird es. Wie seltsam. Falsche Behauptung zurückgezogen und unfaire Ablehnung entfernt.
TessellatingHeckler

1

Sie können das folgende Code-Snippet verwenden. readlines () liest die gesamte Datei auf einmal ein und teilt sie zeilenweise auf.

line = obj.readlines()

0

Zusätzlich zu der großartigen Antwort von @ dawg gibt es die entsprechende Lösung mit dem Walross-Operator (Python> = 3.8):

with open(filename, 'rb') as f:
    while buf := f.read(max_size):
        process(buf)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.