2009-06-24 28 views
15

Gần đây tôi đã gặp phải sự cố do sử dụng fstream :: eof(). Tôi đọc dòng sau từ here:Tại sao std :: fstream đặt bit EOF theo cách của nó?

Hàm eof() trả về true nếu kết thúc tệp đầu vào được kết hợp, sai cách khác.

và (nhầm lẫn) giả định điều này có nghĩa là nếu tôi sử dụng fstream :: read() và đọc phần cuối của tệp, hàm eof() sẽ cho tôi biết. Vì vậy, tôi đã làm một cái gì đó như thế này (rất tổng quát):

for(int i = 0; i < max && !file.eof(); i++) 
{ 
    file.read(mything, sizeof(mything)); 
} 

vấn đề này được đưa ra vì những gì được giải thích sau trên trang liên kết ở trên (mà tôi không thể đọc ban đầu, nhờ vào đoạn đầu tiên nhầm lẫn):

Ngược lại, luồng không đi vào trạng thái EOF nếu có bất kỳ khoảng trống nào sau mã thông báo cuối cùng, nhưng cố gắng đọc một mã thông báo khác vẫn không thành công. Do đó, cờ EOF không thể được sử dụng như một phép thử trong một vòng lặp nhằm đọc tất cả các nội dung luồng cho đến EOF. Thay vào đó, người ta nên kiểm tra tình trạng thất bại sau một nỗ lực để đọc.

Vì vậy, tôi đã thay đổi và giờ đây kiểm tra vòng lặp của tôi dựa vào tệp.fail() thay vì tệp.eof() và tôi hiểu CÁCH eof() hoạt động. Câu hỏi của tôi là, tại sao nó lại hoạt động theo cách đó? Có những tình huống mà điều này là mong muốn không? Dường như với tôi rằng một khi bạn đã vượt qua EOF, bạn đã vượt qua EOF và eof() sẽ trở lại đúng sự thật.

CẬP NHẬT Cảm ơn bạn đã trả lời, tôi nghĩ mình đã hiểu. Hoạt động duy nhất tôi đang thực hiện là đọc(), và tôi ngay lập tức kiểm tra thất bại(), vì vậy tôi nghĩ rằng tôi không sao. Bây giờ, câu hỏi của tôi là, những gì sẽ Tôi sử dụng eof() cho?

+1

cho (int i = 0; i

Trả lời

15

Bởi vì cách này, nó có thể phát hiện EOF mà không biết tệp lớn như thế nào. Tất cả nó phải làm là chỉ đơn giản là cố gắng để đọc và nếu đọc là ngắn (nhưng không phải là một lỗi), sau đó bạn đã đạt đến cuối của tập tin.

Điều này phản ánh chức năng của cuộc gọi hệ thống read, tệp IO thường kết thúc cuộc gọi (win32 có thể gọi ReadFile nhưng tôi tin rằng chức năng này tương tự).

Từ read manpage phần "RETURN VALUE" (nhấn mạnh thêm):

Mở thành công, số lượng byte đọc được trả về (zero chỉ cuối tập tin), và vị trí tập tin là số được nâng cao bởi số này. Đây không phải là lỗi nếu số này nhỏ hơn số byte được yêu cầu; Ví dụ: này có thể xảy ra vì ít hơn byte hiện có sẵn (có thể vì chúng tôi đã gần đến kết thúc tệp hoặc vì chúng tôi đang đọc từ một đường ống hoặc từ nhà ga) hoặc .() bị gián đoạn bởi tín hiệu . Khi lỗi, -1 được trả về và errno được đặt phù hợp. Trong trường hợp này , nó không được chỉ định cho dù vị trí tệp (nếu có) có thay đổi hay không.

BTW: một cách tốt để viết những gì bạn muốn sẽ là như thế này:

T something; 
while(file.read(something, sizeof(something))) { 
    // process your 'something' 
} 

này hoạt động vì file.read (như nhiều thành viên của iostream) trả về một tham chiếu đến iostream riêng của mình. Tất cả đều có một toán tử bị quá tải để cho phép kiểm tra trạng thái luồng. Tương tự như vậy để đọc từ std::cin, while(std::cin >> x) { ... } cũng hoạt động.

CHỈNH SỬA: bạn nên biết rằng thử nghiệm so với thất bại có thể sai như nhau vì lý do tương tự. Từ trang bạn đã liên kết với fail() trả về nếu hoạt động trước đó không thành công. Điều này có nghĩa là bạn cần thực hiện thao tác đọc hoặc hoạt động liên quan khác trước khi kiểm tra.

0
int n; 
std::cin >> n >> std::stripws; 

khắc phục vấn đề này. tại thời điểm đó bạn có thể sử dụng hoặc .good() hoặc .eof(). Tôi thích sử dụng .good(), vì nếu có một khối đĩa xấu, .good() sẽ phát hiện ra nó. nhưng đó là tôi. .eof() sẽ không, bạn cũng sẽ phải thêm .fail() || .xấu().

Tôi chỉ tìm thấy điều này sau một số nghiên cứu khó về vấn đề ăn khoảng trắng. Tôi sẽ đề xuất một ECO cho iostream và ifstream, và lo and behold, nó đã được thực hiện. :-D

Các vấn đề liên quan