Tại sao ifstream.eof () không trả về TRUE sau khi đọc dòng cuối cùng của tệp?


11

Khi một người mới bắt đầu đọc ifuxs, bản năng của anh ấy / cô ấy là đọc tệp bằng một vòng lặp thường trông như thế này:

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

Tuy nhiên, khi tôi sử dụng mã này, tôi nhận thấy rằng nó không dừng lại cho đến khi nó đọc dòng cuối cùng của tệp hai lần. Các lập trình viên C ++ lưu ý rằng đây không thực sự là cách một người nên đọc một tệp. Thay vào đó, họ thường khuyên mọi người cần đọc tệp nên sử dụng một vòng lặp như thế này:

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

Tại sao đoạn mã đầu tiên luôn không hoạt động đúng?


Tôi đã nghĩ sẽ có một bản sao, nhưng tôi không thể tìm thấy ở đây. Có rất nhiều bản sao trên stackoverflow.
David Hammen

Câu trả lời:


4

Các while (!ifstream.eof())vòng lặp không làm việc, vì suối / tập tin trong C và C ++ không dự đoán khi nào bạn đã đạt đến cuối của tập tin, nhưng thay vì chỉ ra nếu bạn đã cố gắng đọc qua phần cuối của tập tin.

Nếu dòng cuối cùng của tệp kết thúc bằng ký tự dòng mới ( \n), thì hầu hết hành động đọc sẽ ngừng đọc khi họ gặp phải ký tự đó và họ không phát hiện ra rằng đó là ký tự cuối cùng trong tệp. Trong hành động đọc tiếp theo, thậm chí có thể có thêm nhiều ký tự được thêm vào và việc đọc sẽ thành công trong việc trích xuất chúng.

Vòng lặp sử dụng toán tử trích xuất luồng ( while (ifstream >> someVar)) hoạt động vì kết quả từ toán tử trích xuất luồng được đánh giá là sai nếu nó không thể trích xuất một mục đúng loại. Điều này cũng xảy ra nếu không còn ký tự để đọc.


4

Tuy nhiên, các lập trình viên C ++ lưu ý rằng điều luôn xảy ra là cin.eof () không trả về "true" cho đến khi dòng cuối cùng được đọc hai lần.

Đó không phải là những gì đang xảy ra. Các eofbitvai trò không có vai trò trong việc chuyển đổi sang boolean ( stream::operator bool(hoặc operator void*trong c ++ cũ hơn)). Chỉ có badbitfailbitcó liên quan.

Giả sử bạn đang đọc một tệp chứa các số được phân tách bằng khoảng trắng. Một vòng lặp dựa trên cin.eof()chắc chắn sẽ là sai hoặc là đầy ắp các ifbài kiểm tra. Bạn không đọc cho đến khi EOF. Bạn đang đọc số. Vì vậy, làm cho mã của bạn thể hiện logic đó:

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

Điều này sẽ hoạt động cho dù dòng cuối cùng của tệp kết thúc bằng 0 42\nhoặc chỉ 0 42(không có dòng mới ở cuối dòng cuối cùng trong tệp). Nếu tệp kết thúc bằng 0 42\n, lần đọc tốt cuối cùng sẽ lấy giá trị 42 và đọc điểm cuối cuối cùng của điểm đánh dấu dòng. Lưu ý rằng điểm đánh dấu EOF chưa được đọc. Các chức năng process_valueđược gọi với 42. Cuộc gọi tiếp theo đến toán tử trích xuất luồng >> đọc EOF và vì không có gì được trích xuất, cả hai eofbitfailbitsẽ được đặt.

Mặt khác, tập tin kết thúc bằng 0 42(không có dòng mới ở cuối dòng cuối cùng). Lần đọc tốt cuối cùng sẽ lấy giá trị 42 kết thúc trên điểm đánh dấu EOF. Có lẽ bạn muốn xử lý 42. Đây là lý do tại sao eofbitkhông đóng vai trò trong toán tử chuyển đổi boolean luồng đầu vào. Trong cuộc gọi tiếp theo đến toán tử trích xuất luồng >>, máy móc bên dưới nhanh chóng thấy rằng thiết eofbitbị đã được đặt. Điều này nhanh chóng dẫn đến việc thiết lập failbit.

Tại sao đoạn mã đầu tiên luôn không hoạt động đúng?

Bởi vì bạn không nên kiểm tra EOF như điều kiện vòng lặp. Điều kiện vòng lặp sẽ diễn tả những gì bạn đang cố gắng thực hiện, đó là (ví dụ), trích xuất các số từ một luồng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.