เหตุใดฉันจึงไม่สามารถเรียก read () สองครั้งในไฟล์ที่เปิดอยู่


100

สำหรับแบบฝึกหัดที่ฉันกำลังทำฉันพยายามอ่านเนื้อหาของไฟล์ที่กำหนดสองครั้งโดยใช้read()วิธีนี้ แปลกจังเมื่อฉันเรียกมันเป็นครั้งที่สองดูเหมือนว่าจะไม่คืนเนื้อหาไฟล์เป็นสตริง?

นี่คือรหัส

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

แน่นอนว่าฉันรู้ว่านี่ไม่ใช่วิธีที่มีประสิทธิภาพที่สุดหรือดีที่สุดนี่ไม่ใช่ประเด็น ประเด็นคือทำไมโทรread()สองครั้งไม่ได้ ฉันต้องรีเซ็ตที่จับไฟล์หรือไม่? หรือปิด / เปิดไฟล์ใหม่เพื่อที่จะทำ?


2
คุณได้แนวคิดมาจากไหนว่าการอ่านแล้วจะไม่เปลี่ยนสถานะของไฟล์ คุณใช้ข้อมูลอ้างอิงหรือบทช่วยสอนอะไร
ล็อ

ฉันเชื่อว่าการปิดและเปิดไฟล์อีกครั้งควรทำงานตามการตรวจสอบด้านล่าง
Anthony

1
@Shynthriir: การปิดและเปิดไฟล์ใหม่ไม่ใช่ความคิดที่ดีเสมอไปเนื่องจากอาจมีเอฟเฟกต์อื่น ๆ ในระบบ (ไฟล์ชั่วคราว incron ฯลฯ )
Ignacio Vazquez-Abrams

3
ผมแค่อยากจะระบุชัดเจน: คุณDIDโทรอ่าน () สองครั้ง!

4
W / R / T / S.Lott และตั้งแต่ 5 ปีเป็นต้นไป: สิ่งนี้จำเป็นต้องมีอยู่ในเอกสาร python ไม่ชัดเจนว่าเราควรคิดว่าการอ่านไฟล์อ็อบเจ็กต์จะเปลี่ยนสถานะของอะไรก็ได้โดยเฉพาะอย่างยิ่งถ้าใครคุ้นเคยกับการทำงานกับข้อมูลที่ไม่เปลี่ยนรูป / การเขียนโปรแกรมรูปแบบการทำงาน ...
Paul Gowder

คำตอบ:


159

การโทรread()จะอ่านทั้งไฟล์และปล่อยให้เคอร์เซอร์อ่านอยู่ท้ายไฟล์ (โดยไม่มีอะไรให้อ่านอีกต่อไป) หากคุณกำลังมองที่จะอ่านจำนวนหนึ่งของสายในช่วงเวลาที่คุณสามารถใช้ readline(), หรือย้ำผ่านเส้นที่มีreadlines()for line in handle:

เพื่อตอบคำถามของคุณโดยตรงเมื่ออ่านไฟล์แล้วread()คุณสามารถใช้seek(0)เพื่อคืนเคอร์เซอร์การอ่านไปที่จุดเริ่มต้นของไฟล์ (เอกสารอยู่ที่นี่ ) หากคุณรู้ว่าไฟล์จะไม่ใหญ่เกินไปคุณยังสามารถบันทึกread()ผลลัพธ์เป็นตัวแปรโดยใช้ในนิพจน์ findall ของคุณ

Ps. อย่าลืมปิดไฟล์หลังจากดำเนินการเสร็จแล้ว;)


4
+1 ใช่โปรดอ่านตัวแปรชั่วคราวเพื่อหลีกเลี่ยงไฟล์ I / O ที่ไม่จำเป็น มันเป็นเศรษฐกิจที่ผิดพลาดที่คุณกำลังบันทึกหน่วยความจำเนื่องจากคุณมีตัวแปร (ชัดเจน) น้อยกว่า
Nick T

2
@NickT: ฉันคาดหวังว่าไฟล์ขนาดเล็กที่อ่านหลาย ๆ ครั้งจะถูกแคชโดย OS (อย่างน้อยบน Linux / OSX) ดังนั้นจึงไม่มีไฟล์ I / O พิเศษสำหรับการอ่านสองครั้ง ไฟล์ขนาดใหญ่ที่ไม่พอดีกับหน่วยความจำจะไม่ถูกแคช แต่คุณไม่ต้องการอ่านเป็นตัวแปรเพราะคุณจะเริ่มสลับ ดังนั้นในกรณีที่มีข้อสงสัยโปรดอ่านหลาย ๆ ครั้งเสมอ หากคุณแน่ใจว่าไฟล์มีขนาดเล็กให้ทำอะไรก็ได้ที่ให้โปรแกรมที่ดีที่สุด
Claude

3
withฉีกลงได้โดยอัตโนมัติด้วย
Cees Timmerman

30

ใช่ข้างบน ...

ฉันจะเขียนแค่ตัวอย่าง:

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

18

ทุกคนที่ตอบคำถามนี้จนถึงตอนนี้มีความถูกต้อง - read()เลื่อนดูไฟล์ดังนั้นหลังจากที่คุณโทรไปแล้วคุณจะไม่สามารถเรียกมันได้อีก

สิ่งที่ฉันจะเพิ่มก็คือในกรณีเฉพาะของคุณคุณไม่จำเป็นต้องย้อนกลับไปที่จุดเริ่มต้นหรือเปิดไฟล์อีกครั้งคุณสามารถจัดเก็บข้อความที่คุณอ่านในตัวแปรท้องถิ่นและใช้สองครั้งหรือ กี่ครั้งก็ได้ในโปรแกรมของคุณ:

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 อันที่จริงนี่เป็นทางออกที่เสนอสำหรับแบบฝึกหัดนี้ ( code.google.com/intl/de-DE/edu/languages/google-python-class/… ) แต่อย่างใดฉันไม่คิดที่จะเก็บสตริงไว้ในตัวแปร โธ่!
วิธีช่วยเหลือ

1
ด้วย Python3 ให้ใช้ pathlib from pathlib import Path; text = Path(filename).read_text()ดูแลเปิดปิด ฯลฯ
PaulMcG

14

ตัวชี้การอ่านจะเลื่อนไปหลังไบต์ / อักขระที่อ่านล่าสุด ใช้seek()วิธีการย้อนกลับตัวชี้การอ่านไปที่จุดเริ่มต้น


2

ทุกไฟล์ที่เปิดมีตำแหน่งที่เกี่ยวข้อง
เมื่อคุณอ่าน () คุณอ่านจากตำแหน่งนั้น ตัวอย่างเช่นread(10)อ่าน 10 ไบต์แรกจากไฟล์ที่เปิดใหม่จากนั้นอีกไฟล์read(10)อ่าน 10 ไบต์ถัดไป read()โดยไม่มีอาร์กิวเมนต์จะอ่านเนื้อหาทั้งหมดของไฟล์โดยปล่อยให้ตำแหน่งไฟล์อยู่ท้ายไฟล์ โทรครั้งหน้าread()ไม่มีอะไรจะอ่าน

คุณสามารถใช้seekเพื่อย้ายตำแหน่งไฟล์ หรืออาจจะดีกว่าในกรณีของคุณคือทำอย่างใดอย่างหนึ่งread()และเก็บผลลัพธ์ไว้สำหรับการค้นหาทั้งสองครั้ง


1

read() กิน ดังนั้นคุณสามารถรีเซ็ตไฟล์หรือหาจุดเริ่มต้นก่อนที่จะอ่านใหม่ หรือถ้ามันเข้ากับงานของคุณคุณสามารถใช้read(n)เพื่อใช้nไบต์เท่านั้น


1

ฉันมักจะพบวิธีการอ่านบางอย่างของการเดินไปตามตรอกมืด ๆ คุณลงไปเล็กน้อยและหยุด แต่ถ้าคุณไม่ได้นับจำนวนก้าวของคุณคุณก็ไม่แน่ใจว่าคุณอยู่ไกลแค่ไหน Seek ให้วิธีแก้ปัญหาโดยการเปลี่ยนตำแหน่งตัวเลือกอื่นคือบอกซึ่งจะส่งคืนตำแหน่งตามไฟล์ อาจเป็นไฟล์ Python api สามารถรวมการอ่านและค้นหาเป็น read_from (ตำแหน่งไบต์) เพื่อให้ง่ายขึ้น - จนกว่าจะเกิดขึ้นคุณควรอ่านหน้านี้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.