Warum kann ich read () in einer geöffneten Datei nicht zweimal aufrufen?

98

Für eine Übung, die ich mache, versuche ich, den Inhalt einer bestimmten Datei zweimal mit der read()Methode zu lesen . Seltsamerweise scheint es beim zweiten Aufruf nicht den Dateiinhalt als Zeichenfolge zurückzugeben?

Hier ist der Code

f = f.open()

# get the year
match = re.search(r'Popularity in (\d+)', f.read())

if match:
  print match.group(1)

# get all the names
matches = re.findall(r'<td>(\d+)</td><td>(\w+)</td><td>(\w+)</td>', f.read())

if matches:
  # matches is always None

Natürlich weiß ich, dass dies nicht der effizienteste oder beste Weg ist, das ist hier nicht der Punkt. Der Punkt ist, warum kann ich nicht read()zweimal anrufen ? Muss ich das Dateihandle zurücksetzen? Oder schließen Sie die Datei, um dies zu tun?

Hilfsmethode
quelle
2
Woher kam die Idee, dass das Lesen den Status der Datei nicht ändern würde? Welche Referenz oder welches Tutorial verwenden Sie?
S.Lott
Ich bin der Meinung, dass das Schließen und erneute Öffnen der Datei auf der Grundlage der folgenden Antworten funktionieren sollte.
Anthony
@Shynthriir: Das Schließen und erneute Öffnen der Datei ist nicht immer eine gute Idee, da dies andere Auswirkungen auf das System haben kann (temporäre Dateien, Inkron usw.).
Ignacio Vazquez-Abrams
3
Ich möchte nur das Offensichtliche sagen : Sie haben read () zweimal aufgerufen!
4
W / R / T / S.Lott und ab 5 Jahren: Dies muss wirklich in der Python-Dokumentation enthalten sein. Es ist nicht offensichtlich, dass man davon ausgehen sollte, dass das Lesen eines
Dateiobjekts den

Antworten:

155

Beim Aufrufen read()wird die gesamte Datei gelesen und der Lesecursor bleibt am Ende der Datei (es bleibt nichts mehr zu lesen). Wenn Sie schauen , um eine bestimmte Anzahl von Zeilen zu einer Zeit , zu lesen , könnten Sie verwenden readline(), readlines()oder durchlaufen Linien mit for line in handle:.

Um Ihre Frage direkt zu beantworten, read()können Sie seek(0)nach dem Lesen einer Datei den Lesecursor an den Anfang der Datei zurücksetzen (Dokumente finden Sie hier ). Wenn Sie wissen, dass die Datei nicht zu groß wird, können Sie die read()Ausgabe auch in einer Variablen speichern und in Ihren Findall-Ausdrücken verwenden.

Ps. Vergessen Sie nicht, die Datei zu schließen, nachdem Sie damit fertig sind;)

Tim
quelle
4
+1, Ja, bitte lesen Sie die temporäre Variable, um unnötige Datei-E / A zu vermeiden. Es ist eine falsche Wirtschaft, dass Sie Speicherplatz sparen, weil Sie weniger (explizite) Variablen haben.
Nick T
2
@NickT: Ich würde erwarten, dass eine kleine Datei, die mehrmals gelesen wird, vom Betriebssystem zwischengespeichert wird (zumindest unter Linux / OSX), also keine zusätzlichen Datei-E / A zum zweimaligen Einlesen. Große Dateien, die nicht in den Speicher passen, werden nicht zwischengespeichert, aber Sie möchten sie nicht in eine Variable einlesen, da Sie mit dem Austauschen beginnen. Lesen Sie im Zweifelsfall immer mehrmals. Wenn Sie sicher sind, dass die Dateien klein sind, tun Sie, was auch immer das schönste Programm ergibt.
Claude
3
Der Abriss kann mit automatisiert werden with.
Cees Timmerman
30

ja wie oben ...

Ich schreibe nur ein Beispiel:

>>> a = open('file.txt')
>>> a.read()
#output
>>> a.seek(0)
>>> a.read()
#same output
Ameise
quelle
17

Jeder, der diese Frage bisher beantwortet hat, hat absolut Recht - read()bewegt sich durch die Datei. Nachdem Sie sie aufgerufen haben, können Sie sie nicht mehr aufrufen.

Was ich hinzufügen möchte, ist, dass Sie in Ihrem speziellen Fall nicht zum Start zurückkehren oder die Datei erneut öffnen müssen, sondern einfach den gelesenen Text in einer lokalen Variablen speichern und zweimal verwenden können, oder so oft du willst, in deinem Programm:

f = f.open()
text = f.read() # read the file into a local variable
# get the year
match = re.search(r'Popularity in (\d+)', text)
if match:
  print match.group(1)
# get all the names
matches = re.findall(r'<td>(\d+)</td><td>(\w+)</td><td>(\w+)</td>', text)
if matches:
  # matches will now not always be None
Tom Anderson
quelle
1
+1 Eigentlich war dies die vorgeschlagene Lösung für diese Übung ( code.google.com/intl/de-DE/edu/languages/google-python-class/… ). Aber irgendwie habe ich nicht daran gedacht, den String in einer Variablen zu speichern. D'oh!
Hilfsmethode
1
Verwenden Sie in Python3 pathlib. from pathlib import Path; text = Path(filename).read_text()
Kümmert sich
14

Der Lesezeiger bewegt sich nach dem letzten gelesenen Byte / Zeichen. Verwenden Sie die seek()Methode, um den Lesezeiger auf den Anfang zurückzuspulen.

Ignacio Vazquez-Abrams
quelle
2

Jeder geöffneten Datei ist eine Position zugeordnet.
Wenn Sie () lesen, lesen Sie von dieser Position aus. read(10)Liest beispielsweise die ersten 10 Bytes aus einer neu geöffneten Datei, dann read(10)liest eine andere die nächsten 10 Bytes. read()ohne Argumente liest den gesamten Inhalt der Datei und belässt die Dateiposition am Ende der Datei. Wenn Sie das nächste Mal anrufen, read()gibt es nichts zu lesen.

Mit können Sie die Dateiposition seekverschieben. Oder wahrscheinlich wäre es in Ihrem Fall besser, eine read()durchzuführen und das Ergebnis für beide Suchvorgänge beizubehalten.

Douglas Leeder
quelle
1

read() verbraucht . So können Sie zurücksetzen die Datei, oder versuchen , zu Beginn vor dem erneuten Lesen. Wenn es Ihrer Aufgabe entspricht, können Sie auch read(n)nur nBytes verwenden.

Towi
quelle
1

Ich finde die Lesemethode immer so etwas wie einen Spaziergang durch eine dunkle Gasse. Du gehst ein bisschen runter und hörst auf, aber wenn du deine Schritte nicht zählst, bist du dir nicht sicher, wie weit du bist. Seek gibt die Lösung durch Neupositionierung, die andere Option ist Tell, die die Position entlang der Datei zurückgibt. Möglicherweise kann die Python-Datei-API Lese- und Suchvorgänge in read_from (Position, Bytes) kombinieren, um dies zu vereinfachen. Bis dahin sollten Sie diese Seite lesen .

Whatnick
quelle