getline 设置 failbit 和 eof
getline setting failbit along with eof
我知道这种行为的起源,因为它在 SO 的多篇文章中得到了很好的解释,一些值得注意的例子是:
Why is iostream::eof inside a loop condition considered wrong?
Use getline() without setting failbit
std::getline throwing when it hits eof
C++ istream EOF does not guarantee failbit?
并且它也包含在std::getline
standard中:
3) If no characters were extracted for whatever reason (not even the discarded delimiter), getline sets failbit and returns.
我的问题是如何处理这种行为,您希望您的流在所有情况下捕获 failbit
异常,但由于到达文件的 eof
而导致的异常除外最后一行是空的。有什么明显的我想念的吗?
MWE:
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
void f(const std::string & file_name, char comment) {
std::ifstream file(file_name);
file.exceptions(file.failbit);
try {
std::string line;
while (std::getline(file, line).good()) {
// empty getline sets failbit throwing an exception
if ((line[0] != comment) && (line.size() != 0)) {
std::stringstream ss(line);
// do stuff
}
}
}
catch (const std::ios_base::failure& e) {
std::cerr << "Caught an ios_base::failure.\n"
<< "Explanatory string: " << e.what() << '\n'
<< "Error code: " << e.code() << '\n';
}
}
int main() {
f("example.txt", '#');
}
其中 example.txt 是一个制表符分隔的文件,其最后一行仅为 \n
字符:
# This is a text file meant for testing
0 9
1 8
2 7
编辑:
while(std::getline(file, line).good()){...}
重复问题。
编辑:我误解了OP,参考上面David的回答。此答案用于检查文件是否有终止换行符。
在 while (getline)
循环结束时,检查 file.eof()
。
假设您刚刚对文件的最后一行做了 std::getline()
。
如果后面有\n
,那么std::getline()
已经读取了分隔符,没有设置eofbit
。 (在这种情况下,下一个 std::getline()
将设置 eofbit
。)
而如果后面没有\n
,则std::getline()
读取了EOF并设置了eofbit
。
在这两种情况下,下一个 std::getline()
将触发 failbit
并进入您的异常处理程序。
PS:如果 line
为空,则 if ((line[0] != comment) && (line.size() != 0)) {
行是 UB。需要颠倒条件的顺序。
另一种避免设置 failbit
的方法是重构您的 if
测试以检测 空行 的读取。因为在这种情况下这是你的最后一行,你可以简单地 return
来避免抛出错误,例如:
std::ifstream file (file_name);
file.exceptions (file.failbit);
try {
std::string line;
while (std::getline(file, line)) {
// detect empty line and return
if (line.size() == 0)
return;
if (line[0] != comment) {
std::stringstream ss(line);
// do stuff
}
}
}
...
您的另一个选择是检查 eofbit
是否设置在 catch
中。如果设置了 eofbit
——读取成功完成。例如
catch (const std::ios_base::failure& e) {
if (!file.eof())
std::cerr << "Caught an ios_base::failure.\n"
<< "Explanatory string: " << e.what() << '\n'
<< "Error code: " /* << e.code() */ << '\n';
}
我知道这种行为的起源,因为它在 SO 的多篇文章中得到了很好的解释,一些值得注意的例子是:
Why is iostream::eof inside a loop condition considered wrong?
Use getline() without setting failbit
std::getline throwing when it hits eof
C++ istream EOF does not guarantee failbit?
并且它也包含在std::getline
standard中:
3) If no characters were extracted for whatever reason (not even the discarded delimiter), getline sets failbit and returns.
我的问题是如何处理这种行为,您希望您的流在所有情况下捕获 failbit
异常,但由于到达文件的 eof
而导致的异常除外最后一行是空的。有什么明显的我想念的吗?
MWE:
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
void f(const std::string & file_name, char comment) {
std::ifstream file(file_name);
file.exceptions(file.failbit);
try {
std::string line;
while (std::getline(file, line).good()) {
// empty getline sets failbit throwing an exception
if ((line[0] != comment) && (line.size() != 0)) {
std::stringstream ss(line);
// do stuff
}
}
}
catch (const std::ios_base::failure& e) {
std::cerr << "Caught an ios_base::failure.\n"
<< "Explanatory string: " << e.what() << '\n'
<< "Error code: " << e.code() << '\n';
}
}
int main() {
f("example.txt", '#');
}
其中 example.txt 是一个制表符分隔的文件,其最后一行仅为 \n
字符:
# This is a text file meant for testing
0 9
1 8
2 7
编辑:
while(std::getline(file, line).good()){...}
重复问题。
编辑:我误解了OP,参考上面David的回答。此答案用于检查文件是否有终止换行符。
在 while (getline)
循环结束时,检查 file.eof()
。
假设您刚刚对文件的最后一行做了 std::getline()
。
如果后面有
\n
,那么std::getline()
已经读取了分隔符,没有设置eofbit
。 (在这种情况下,下一个std::getline()
将设置eofbit
。)而如果后面没有
\n
,则std::getline()
读取了EOF并设置了eofbit
。
在这两种情况下,下一个 std::getline()
将触发 failbit
并进入您的异常处理程序。
PS:如果 line
为空,则 if ((line[0] != comment) && (line.size() != 0)) {
行是 UB。需要颠倒条件的顺序。
另一种避免设置 failbit
的方法是重构您的 if
测试以检测 空行 的读取。因为在这种情况下这是你的最后一行,你可以简单地 return
来避免抛出错误,例如:
std::ifstream file (file_name);
file.exceptions (file.failbit);
try {
std::string line;
while (std::getline(file, line)) {
// detect empty line and return
if (line.size() == 0)
return;
if (line[0] != comment) {
std::stringstream ss(line);
// do stuff
}
}
}
...
您的另一个选择是检查 eofbit
是否设置在 catch
中。如果设置了 eofbit
——读取成功完成。例如
catch (const std::ios_base::failure& e) {
if (!file.eof())
std::cerr << "Caught an ios_base::failure.\n"
<< "Explanatory string: " << e.what() << '\n'
<< "Error code: " /* << e.code() */ << '\n';
}