Mengapa saya tidak dapat memanggil read () dua kali pada file yang terbuka?

100

Untuk latihan yang saya lakukan, saya mencoba membaca konten file dua kali menggunakan read()metode ini. Anehnya, ketika saya menyebutnya untuk kedua kalinya, sepertinya tidak mengembalikan konten file sebagai string?

Ini kodenya

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

Tentu saja saya tahu bahwa ini bukan cara yang paling efisien atau terbaik, bukan itu intinya di sini. Intinya adalah, mengapa saya tidak bisa menelepon read()dua kali? Apakah saya harus mengatur ulang pegangan file? Atau tutup / buka kembali file untuk melakukan itu?

metode pembantu
sumber
2
Dari mana Anda mendapatkan gagasan bahwa membaca tidak akan mengubah status file? Referensi atau tutorial apa yang Anda gunakan?
S. Lotot
Saya percaya menutup dan membuka kembali file harus bekerja berdasarkan jawaban di bawah ini.
Anthony
1
@Shynthriir: Menutup dan membuka kembali file tidak selalu merupakan ide yang baik karena mungkin memiliki efek lain dalam sistem (file sementara, incron, dll.).
Ignacio Vazquez-Abrams
3
Saya hanya ingin menyatakan yang sudah jelas: Anda MELAKUKAN panggilan read () dua kali!
4
W / R / T / S. Lott, dan dari 5 tahun ke depan: ini benar-benar perlu ada di dokumentasi python. Tidak jelas bahwa seseorang harus berasumsi bahwa membaca objek file akan mengubah status apa pun, terutama jika seseorang terbiasa bekerja dengan pemrograman gaya data / fungsional yang tidak dapat diubah ...
Paul Gowder

Jawaban:

157

Panggilan read()membaca seluruh file dan meninggalkan kursor baca di akhir file (tidak ada lagi yang bisa dibaca). Jika Anda ingin membaca sejumlah baris sekaligus, Anda dapat menggunakan readline(), readlines()atau mengulang baris dengan for line in handle:.

Untuk menjawab pertanyaan Anda secara langsung, setelah file dibaca, dengan read()Anda dapat menggunakan seek(0)untuk mengembalikan kursor baca ke awal file (dokumen ada di sini ). Jika Anda tahu bahwa file tidak akan terlalu besar, Anda juga dapat menyimpan read()hasilnya ke variabel, menggunakannya dalam ekspresi findall Anda.

Ps. Jangan lupa untuk menutup file setelah Anda selesai;)

Tim
sumber
4
+1, Ya, harap baca ke variabel sementara untuk menghindari I / O file yang tidak perlu. Ini adalah ekonomi palsu bahwa Anda menyimpan memori apa pun karena Anda memiliki lebih sedikit variabel (eksplisit).
Nick T
2
@NickT: Saya berharap bahwa file kecil yang dibaca beberapa kali akan di-cache oleh OS (setidaknya di Linux / OSX), jadi tidak ada file tambahan I / O untuk dibaca dua kali. File besar yang tidak muat dalam memori tidak akan di-cache, tetapi Anda tidak ingin membacanya menjadi variabel karena Anda akan mulai bertukar. Jadi jika ragu, selalu baca berkali-kali. Jika Anda tahu pasti bahwa file tersebut kecil, lakukan apa pun yang memberikan program terbaik.
Claude
3
Tear down dapat diotomatiskan dengan with.
Cees Timmerman
30

ya, seperti di atas ...

saya akan menulis hanya sebuah contoh:

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

Setiap orang yang telah menjawab pertanyaan ini sejauh ini benar - read()menelusuri file, jadi setelah Anda memanggilnya, Anda tidak dapat memanggilnya lagi.

Apa yang akan saya tambahkan adalah bahwa dalam kasus khusus Anda, Anda tidak perlu mencari kembali ke awal atau membuka kembali file, Anda cukup menyimpan teks yang telah Anda baca dalam variabel lokal, dan menggunakannya dua kali, atau sebanyak yang Anda suka, dalam program Anda:

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
sumber
1
+1 Sebenarnya ini adalah solusi yang diusulkan untuk latihan ini ( code.google.com/intl/de-DE/edu/languages/google-python-class/… ). Tapi entah mengapa saya tidak berpikir untuk menyimpan string dalam variabel. D'oh!
helpermethod
1
Dengan Python3, gunakan pathlib. from pathlib import Path; text = Path(filename).read_text()Menjaga pembukaan, penutupan, dll.
PaulMcG
14

Penunjuk baca berpindah ke setelah byte / karakter baca terakhir. Gunakan seek()metode untuk memundurkan penunjuk baca ke awal.

Ignacio Vazquez-Abrams
sumber
2

Setiap file terbuka memiliki posisi terkait.
Ketika Anda membaca () Anda membaca dari posisi itu. Misalnya read(10)membaca 10 byte pertama dari file yang baru dibuka, kemudian yang lain read(10)membaca 10 byte berikutnya. read()tanpa argumen membaca semua konten file, meninggalkan posisi file di akhir file. Lain kali Anda menelepon, read()tidak ada yang bisa dibaca.

Anda dapat menggunakan seekuntuk memindahkan posisi file. Atau mungkin lebih baik dalam kasus Anda adalah melakukan satu read()dan menyimpan hasilnya untuk kedua pencarian.

Douglas Leeder
sumber
1

read() mengkonsumsi . Jadi, Anda dapat mengatur ulang file, atau mencoba memulai sebelum membaca ulang. Atau, jika itu menggabungkan tugas Anda, Anda dapat menggunakan read(n)untuk hanya menggunakan nbyte.

towi
sumber
1

Saya selalu menemukan metode membaca sesuatu seperti berjalan menyusuri gang gelap. Anda turun sedikit dan berhenti tetapi jika Anda tidak menghitung langkah Anda, Anda tidak yakin seberapa jauh Anda melangkah. Seek memberikan solusi dengan memposisikan ulang, opsi lainnya adalah Tell yang mengembalikan posisi di sepanjang file. Mungkin api file Python dapat menggabungkan read dan seek menjadi read_from (position, bytes) untuk membuatnya lebih sederhana - sampai itu terjadi Anda harus membaca halaman ini .

whatnick
sumber