ทำไม ifstream.eof () ไม่ส่งคืน TRUE หลังจากอ่านบรรทัดสุดท้ายของไฟล์


11

เมื่อมือใหม่เริ่มอ่าน ifstreams สัญชาตญาณของเขา / เธอคือการอ่านไฟล์โดยใช้ลูปที่มักจะมีลักษณะดังนี้

while (!ifstream.eof()
{
...
}

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

while (ifstream >> someVar)
{
...
}

ทำไมรหัสชิ้นแรกไม่สามารถทำงานได้อย่างถูกต้อง?


ฉันคิดว่าจะมีสิ่งที่ซ้ำกัน แต่ฉันไม่พบที่นี่ มีการทำซ้ำมากมายใน stackoverflow
David Hammen

คำตอบ:


4

while (!ifstream.eof())ห่วงไม่ทำงานเพราะกระแส / ไฟล์ใน C และ C ++ ไม่ได้คาดการณ์เมื่อคุณได้มาถึงจุดสิ้นสุดของแฟ้ม แต่ค่อนข้างแสดงว่าคุณได้พยายามที่จะอ่านที่ผ่านมาในตอนท้ายของแฟ้ม

หากบรรทัดสุดท้ายของไฟล์ลงท้ายด้วยอักขระขึ้นบรรทัดใหม่ ( \n) การดำเนินการอ่านส่วนใหญ่จะหยุดอ่านเมื่อพบอักขระนั้นและพวกเขาไม่พบว่าเกิดขึ้นเป็นอักขระตัวสุดท้ายในไฟล์ ในการดำเนินการอ่านครั้งถัดไปอาจเป็นไปได้ว่ามีการเพิ่มตัวอักขระเพิ่มเติมและการอ่านจะประสบความสำเร็จในการแยก

การวนซ้ำโดยใช้ตัวดำเนินการดึงข้อมูล ( while (ifstream >> someVar)) ทำงานได้เนื่องจากผลลัพธ์จากตัวดำเนินการแยกข้อมูลประเมินเป็นเท็จหากไม่สามารถแยกรายการประเภทที่เหมาะสมได้ สิ่งนี้จะเกิดขึ้นหากไม่มีตัวอักษรเหลือให้อ่าน


4

อย่างไรก็ตามโปรแกรมเมอร์ C ++ โปรดทราบว่าสิ่งที่เกิดขึ้นเสมอคือ cin.eof () จะไม่ส่งกลับ "true" จนกระทั่งหลังจากอ่านบรรทัดสุดท้ายสองครั้ง

นั่นไม่ใช่สิ่งที่เกิดขึ้น การeofbitเล่นไม่มีบทบาทในการแปลงเป็นบูลีน ( stream::operator bool(หรือoperator void*ใน c ++ เก่ากว่า) เฉพาะbadbitและfailbitมีส่วนร่วม

สมมติว่าคุณกำลังอ่านไฟล์ที่มีตัวเลขคั่นด้วยช่องว่าง การวนซ้ำที่อยู่รอบ ๆcin.eof()นั้นอาจจะผิดหรือทำให้ifการทดสอบเต็มไปหมด คุณไม่ได้อ่านจนกระทั่ง EOF คุณกำลังอ่านตัวเลข เพื่อให้รหัสของคุณแสดงตรรกะที่:

while (stream >> some_var) {
    process_value(some_var);
}

วิธีนี้จะทำงานไม่ว่าบรรทัดสุดท้ายของไฟล์จะลงท้ายด้วย0 42\nหรือเพียงแค่0 42(ไม่มีบรรทัดใหม่ที่ท้ายบรรทัดสุดท้ายในไฟล์) หากไฟล์ลงท้ายด้วย0 42\nการอ่านที่ดีครั้งสุดท้ายจะดึงค่า 42 และอ่านตัวทำเครื่องหมายบรรทัดสุดท้ายที่ โปรดทราบว่าเครื่องหมาย EOF ยังไม่ได้อ่าน ฟังก์ชั่นเรียกว่ามีprocess_value 42การเรียกครั้งต่อไปที่โอเปอเรเตอร์การดึงข้อมูล >> อ่าน EOF และเนื่องจากไม่มีการแตกไฟล์ใด ๆ ทั้งeofbitและfailbitจะถูกตั้งค่า

สมมติว่าไฟล์นั้นลงท้ายด้วย0 42(ไม่มีการขึ้นบรรทัดใหม่ที่ท้ายบรรทัดสุดท้าย) การอ่านที่ดีครั้งสุดท้ายจะดึงค่า 42 ที่ยกเลิกบนเครื่องหมาย EOF สันนิษฐานว่าคุณต้องการประมวลผลที่ 42 นี่คือสาเหตุที่eofbitไม่มีบทบาทในตัวดำเนินการแปลงบูลีนสตรีมอินพุต ในการเรียกครั้งต่อไปที่ผู้ดำเนินการดึงข้อมูล >> เครื่องจักรพื้นฐานจะเห็นว่าeofbitมีการตั้งค่าไว้แล้ว failbitนี้ได้อย่างรวดเร็วส่งผลในการตั้งค่า

ทำไมรหัสชิ้นแรกไม่สามารถทำงานได้อย่างถูกต้อง?

เพราะคุณไม่ควรตรวจสอบ EOF ว่าเป็นเงื่อนไขลูป เงื่อนไขการวนซ้ำควรแสดงสิ่งที่คุณพยายามทำซึ่งก็คือ (ตัวอย่าง) การแยกตัวเลขจากสตรีม

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