#include <iostream>
#include <fstream>
int main() {
std::fstream inf( "ex.txt", std::ios::in );
while( !inf.eof() ) {
std::cout << inf.get() << "\n";
}
inf.close();
inf.clear();
inf.open( "ex.txt", std::ios::in );
char c;
while( inf >> c ) {
std::cout << c << "\n";
}
return 0;
}
我对eof()
功能感到困惑。假设我的ex.txt的内容是:
abc
在使用-1
阅读时,它总是会读取额外字符并显示eof()
。但inf >> c
给出的正确输出是'abc'?任何人都可以帮我解释一下吗?
答案 0 :(得分:67)
-1是get
说你到达文件末尾的方式。使用std::char_traits<char>::eof()
(或std::istream::traits_type::eof()
)比较它 - 避免-1,这是一个神奇的数字。 (虽然另一个有点冗长 - 你可以随时拨打istream::eof
)
仅当读取尝试读取超过文件末尾时,才会设置EOF标志。如果我有一个3字节的文件,而我只读取3个字节,则EOF为false
,因为我还没有尝试读取文件的末尾。虽然这对于通常知道其大小的文件来说似乎有些混乱,但在某些设备(例如管道和网络套接字)上尝试读取之前,EOF是未知的。
第二个示例有效,因为inf >> foo
将始终返回inf
,其副作用是尝试读取内容并将其存储在foo
中。如果文件“良好”,inf
或if
中的while
将评估为true
:没有错误,没有EOF。因此,当读取失败时,inf
会传播到false
,并且您的循环会正常中止。但是,请采取以下常见错误:
while(!inf.eof()) // EOF is false here
{
inf >> x; // read fails, EOF becomes true, x is not set
// use x // we use x, despite our read failing.
}
但是,这个:
while(inf >> x) // Attempt read into x, return false if it fails
{
// will only be entered if read succeeded.
}
这就是我们想要的。
答案 1 :(得分:7)
iostream不知道它在文件的末尾,直到它尝试读取超过文件末尾的第一个字符。
sample code at cplusplus.com说这样做:(但你不应该这样做)
while (is.good()) // loop while extraction from file is possible
{
c = is.get(); // get character from file
if (is.good())
cout << c;
}
更好的习惯用法是将读取移动到循环条件中,如下所示:
(您可以使用返回istream
的所有 *this
读取操作执行此操作,包括>>
运算符)
char c;
while(is.get(c))
cout << c;
答案 2 :(得分:6)
EOF标志仅在读取操作尝试读取超过文件末尾后设置。 get()
返回符号常量traits::eof()
(恰好等于-1),因为它到达文件的末尾并且无法读取更多数据,并且仅在此时eof()
int ch;
while ((ch = inf.get()) != EOF) {
std::cout << static_cast<char>(ch) << "\n";
}
} 是真的。如果要检查此情况,可以执行以下操作:
{{1}}
答案 3 :(得分:2)
eof()检查流状态中的eofbit。
在每次读取操作中,如果位置在流的末尾并且必须读取更多数据,则eofbit设置为true。因此,在获得eofbit = 1之前,您将获得额外的字符。
正确的方法是在读取操作之后检查是否已达到eof(或读取操作是否成功)。这是您的第二个版本所做的 - 您执行读取操作,然后使用生成的流对象引用(&gt;&gt;返回)作为布尔值,这将导致检查fail()。