如何使用 ifstream 正确从文件中读取 unsigned int 变量?
我的代码从文本文件 Input_File_Name
读取 unsigned int 变量。
unsigned int Column_Count; //Cols
unsigned int Row_Count;//Rows
try {
ifstream input_stream;
input_stream.open(Input_File_Name,ios_base::in);
if (input_stream) {
//if file is opened
input_stream.exceptions(ios::badbit | ios::failbit);
input_stream>>Row_Count;
input_stream>>Column_Count;
} else {
throw std::ios::failure("Can't open input file");
//cout << "Error: Can't open input file" << endl;
}
} catch (const ios::failure& error) {
cout << "Oh No!!" << error.what() << endl;
} catch (const exception& error) {
cout << error.what() <<"Oh No!!" << endl;
} catch (...) {
cout << "Unknown exception" << endl;
}
效果非常好。 但是,当我用错误的数据填充文本文件时,
33abcd4 567fg8
它的工作方式如下:
input_stream>>Row_Count; //Row_Count = 33;
input_stream>>Column_Count; // throws an ios::failure exception
为什么此行 input_stream>>Row_Count;
不抛出异常?
据我了解, input_stream 将任何非数字符号视为分隔符,下一步它会尝试读取“abcd”。是这样吗?
如何设置空格符号作为分隔符,以便在读取“33abcd4”时从这行代码 input_stream>>Row_Count;
引发 ios::failure
异常?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果流可以读取任何整数值,则整数值的正常提取会成功。也就是说,如果至少有一位数字可选地后跟任何内容,则整数读取成功。正常的提取操作不会尝试读取更多内容,特别是它们不会尝试查找下一个空格。
从它的声音来看,您需要确保您的号码后面有一个空格,如果没有则失败。我可以想到两种不同的方法来执行此操作:
in >> 之类的方式读取您的值。值>> is_space
。std::num_get
构面,将其安装到std::locale
中,并imbue()
此std::locale
到您的流中。它涉及更多一些,但不需要对整数的读取方式进行任何更改。创建这样的操纵器相当简单:
现在,改变数字的读取方式更有趣,我怀疑我刚刚命名了许多大多数人都不太了解的标准库类。因此,让我们也快速为此键入一个示例。我将仅更改 std::num_get 方面来处理
unsigned int
:要对其他整数类型执行此操作,需要重写更多函数。因此,这里是std::num_get
方面的替代:这一切都是从
std::num_get
派生一个类并覆盖一个类其虚函数。这个函数的实现相当简单:首先通过委托给基类来读取值(我刚刚意识到虚拟函数确实想要保护而不是像我过去那样私有,但这是一个完全不同的讨论) 。无论是否成功(如果不成功,它将在 err 中设置错误状态),覆盖都会检查是否有另一个可用字符,如果有,则检查它是否是空格,如果不是则设置err中的>std::ios_base::failbit。
剩下的就是设置流以在
std::locale
中使用此特定方面,并将新的std::locale
挂接到流中:std ::locale
及其 Facet 是内部引用计数的,即您不应该跟踪指向 Facet 的指针,也不需要保留std::locale
任何一个。如果imbue()
创建的std::locale
看起来很麻烦,或者你想在任何地方使用这个修改后的逻辑,你可以设置全局std ::locale
用于初始化任何新创建的流以使用自定义std::num_get
方面。The normal extraction of an integer value succeeds if the stream could read any integer value. That is, if there is at least one digit optionally followed by anything the read of an integer succeeds. The normal extraction operations don't try to read more, in particular they don't try to find the next whitespace.
From the sounds of it, you want to be sure that there is a whitespace following your number and fail if there is not. I can think of two different approaches to do this:
in >> value >> is_space
.std::num_get<char>
facet, install it into astd::locale
, andimbue()
thisstd::locale
into your stream(s). It is a bit more involved but doesn't require any changes to the way integers are read.Creating a manipulator like this is fairly trivial:
Now, changing the way numbers are read is more interesting and I suspect I had just named a number of standard library classes most people are fairly unaware of. So, let's quickly type out an example for this as well. I will change the
std::num_get<char>
facet only to deal withunsigned int
: to do it for other integral types it is necessary to override more functions. So, here is a replacement for thestd::num_get<char>
facet:All this does is to derive a class from
std::num_get<char>
and override one of its virtual functions. The implementation of this function is fairly straight forward: start with reading the value by delegating to the base class (I just realized that virtual functions indeed want to protected rather than private as I have though in the past but this is an entirely different discussion). Independent of whether this was successful (if it was not, it will have set up an error state in err) the override checks if there is another character available and, if so, checks if it is a space and if not sets astd::ios_base::failbit
in the error resulterr
.What remains is to set up the stream to use this particular facet in a
std::locale
and hook the newstd::locale
into a stream:The
std::locale
s and its facets are internally reference counted, i.e. you shouldn't keep track of the pointer to the facet and you don't need to keep thestd::locale
around either. If it seems to be to cumbersome toimbue()
the createdstd::locale
or you want to use this modified logic everywhere, you can set the globalstd::locale
which is used to initialize any newly created stream to use the customstd::num_get<char>
facet.您可以这样做:
如果您希望这也适用于其他类型,请以相同的方式实现以下内容:
其中 T 是
bool
、long
之一,长长
、无符号短
、无符号长
、无符号长长
、浮点
、double
、long double
和无效*
。You can do it this way:
If you want this to work for other types too, then implement the following in the same way:
where T is one of
bool
,long
,long long
,unsigned short
,unsigned long
,unsigned long long
,float
,double
,long double
andvoid*
.