Perché non posso chiamare read () due volte su un file aperto?


100

Per un esercizio che sto facendo, cerco di leggere due volte il contenuto di un dato file usando il read()metodo. Stranamente, quando lo chiamo la seconda volta, non sembra restituire il contenuto del file come una stringa?

Ecco il codice

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

Ovviamente so che questo non è il modo più efficiente o migliore, non è questo il punto qui. Il punto è, perché non posso chiamare read()due volte? Devo ripristinare l'handle del file? O chiudere / riaprire il file per farlo?


2
Dove hai avuto l'idea che la lettura non avrebbe cambiato lo stato del file? Quale riferimento o tutorial stai usando?
S.Lott

Credo che la chiusura e la riapertura del file dovrebbe funzionare in base alle risposte seguenti.
Anthony,

1
@Shynthriir: chiudere e riaprire il file non è sempre una buona idea poiché potrebbe avere altri effetti nel sistema (file temporanei, incron, ecc.).
Ignacio Vazquez-Abrams,

3
Voglio solo affermare l'ovvio: HAI CHIAMATO read () due volte!

4
W / R / T / S.Lott, e da 5 anni in poi: questo deve davvero essere nella documentazione di Python. Non è ovvio che si debba presumere che la lettura di un oggetto file cambierebbe lo stato di qualsiasi cosa, specialmente se si è abituati a lavorare con dati immutabili / programmazione in stile funzionale ...
Paul Gowder

Risposte:


157

La chiamata read()legge l'intero file e lascia il cursore di lettura alla fine del file (senza più niente da leggere). Se stai cercando di leggere un certo numero di righe alla volta si potrebbe usare readline(), readlines()o iterare linee con for line in handle:.

Per rispondere direttamente alla tua domanda, una volta che un file è stato letto, read()puoi usare seek(0)per riportare il cursore di lettura all'inizio del file (i documenti sono qui ). Se sai che il file non sarà troppo grande, puoi anche salvare l' read()output in una variabile, utilizzandolo nelle espressioni findall.

Ps. Non dimenticare di chiudere il file dopo averlo finito;)


4
+1, Sì, leggere la variabile temporanea per evitare I / O di file non necessari. È una falsa economia risparmiare memoria perché hai meno variabili (esplicite).
Nick T

2
@ NickT: mi aspetto che un piccolo file letto più volte venga memorizzato nella cache dal sistema operativo (almeno su Linux / OSX), quindi nessun I / O di file aggiuntivo per la lettura due volte. I file di grandi dimensioni che non si adattano alla memoria non vengono memorizzati nella cache, ma non vuoi leggerli in una variabile perché inizierai a scambiare. Quindi, in caso di dubbio, leggi sempre più volte. Se sai per certo che i file sono piccoli, fai quello che ti dà il programma migliore.
Claude

3
Lo smontaggio può essere automatizzato con with.
Cees Timmerman

30

si, come sopra ...

scriverò solo un esempio:

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

17

Chiunque abbia risposto a questa domanda finora ha assolutamente ragione: si read()sposta nel file, quindi dopo averlo chiamato non è più possibile richiamarlo.

Quello che aggiungerò è che nel tuo caso particolare, non è necessario tornare all'inizio o riaprire il file, puoi semplicemente memorizzare il testo che hai letto in una variabile locale e usarlo due volte, oppure tutte le volte che vuoi, nel tuo programma:

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

1
+1 In realtà questa era la soluzione proposta per questo esercizio ( code.google.com/intl/de-DE/edu/languages/google-python-class/… ). Ma in qualche modo non ho pensato di memorizzare la stringa in una variabile. D'oh!
helpermethod

1
Con Python3, usa pathlib. from pathlib import Path; text = Path(filename).read_text()Si occupa di aprire, chiudere, ecc.
PaulMcG

14

Il puntatore di lettura si sposta dopo l'ultimo byte / carattere letto. Usa il seek()metodo per riavvolgere il puntatore di lettura all'inizio.


2

Ogni file aperto ha una posizione associata.
Quando leggi () leggi da quella posizione. Ad esempio, read(10)legge i primi 10 byte da un file appena aperto, quindi un altro read(10)legge i successivi 10 byte. read()senza argomenti legge tutto il contenuto del file, lasciando la posizione del file alla fine del file. La prossima volta che chiami read()non c'è niente da leggere.

È possibile utilizzare seekper spostare la posizione del file. O probabilmente nel tuo caso sarebbe meglio farne uno read()e mantenere il risultato per entrambe le ricerche.


1

read() consuma . Quindi, puoi ripristinare il file o cercare l'inizio prima di rileggerlo. Oppure, se si adatta alla tua attività, puoi utilizzare read(n)per consumare solo nbyte.


1

Trovo sempre il metodo di lettura qualcosa di simile a una passeggiata in un vicolo buio. Scendi un po 'e ti fermi ma se non conti i tuoi passi non sei sicuro di quanto sei lontano. Seek fornisce la soluzione riposizionando, l'altra opzione è Tell che restituisce la posizione lungo il file. Potrebbe essere che l'api del file Python possa combinare read e seek in read_from (posizione, byte) per renderlo più semplice - finché ciò non accade dovresti leggere questa pagina .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.