如何使用 ifstream 正确从文件中读取无符号的 int 变量
How to read unsigned int variables from file correctly, using ifstream?
我的代码从文本文件中读取无符号的 int 变量Input_File_Name
.
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
异常?
如果流可以读取任何整数值,则整数值的正常提取成功。也就是说,如果至少有一个数字可以选择后跟任何数字,则整数的读取会成功。正常的提取操作不会尝试读取更多内容,特别是它们不会尝试查找下一个空格。
从它的声音来看,您希望确保您的号码后面有一个空格,如果没有,则失败。我可以想到两种不同的方法来做到这一点:
- 创建一个简单的操纵器,用于检查流是否位于空格字符上。但是,这意味着您将使用类似
in >> value >> is_space
的内容读取您的值。 - 创建自定义
std::num_get<char>
分面,将其安装到std::locale
中,然后将此std::locale
imbue()
到流中。它涉及更多,但不需要对读取整数的方式进行任何更改。
创建这样的操纵器是相当微不足道的:
std::istream& is_space(std::istream& in)
{
if (!std::isspace(in.peek()))
{
in.setstate(std::ios_base::failbit);
}
return in;
}
现在,改变数字的读取方式更有趣,我怀疑我刚刚命名了一些大多数人都不知道的标准库类。因此,让我们快速键入一个示例。我将更改std::num_get<char>
方面只是为了处理unsigned int
:要为其他积分类型执行此操作,有必要覆盖更多函数。因此,这里是std::num_get<char>
方面的替代品:
class num_get:
public std::num_get<char>
{
iter_type do_get(iter_type it, iter_type end,
std::ios_base& ios, std::ios_base::iostate& err,
unsigned int& value) const
{
it = std::num_get<char>::do_get(it, end, ios, err, value);
if (it != end && !isspace(static_cast<unsigned char>(*it)))
{
err |= std::ios_base::failbit;
}
return it;
}
};
所有这些作用都是从std::num_get<char>
派生一个类并覆盖其虚函数之一。这个函数的实现相当简单:从通过委托给基类来读取值开始(我刚刚意识到虚拟函数确实想要保护而不是像过去那样私有,但这是一个完全不同的讨论(。无论这是否成功(如果没有,它将在 err 中设置错误状态(覆盖检查是否有另一个字符可用,如果是,则检查它是否是一个空格,如果没有,则在错误结果中设置std::ios_base::failbit
err
。
剩下的就是设置流以在std::locale
中使用此特定方面,并将新std::locale
挂接到流中:
std::locale loc(std::locale(), new num_get);
in.imbue(loc);
std::locale
s 及其分面在内部进行引用计数,即您不应该跟踪指向分面的指针,也不需要保留std::locale
。如果imbue()
创建的std::locale
似乎很麻烦,或者您想在任何地方使用此修改后的逻辑,则可以设置用于初始化任何新创建的流的全局std::locale
以使用自定义std::num_get<char>
方面。
你可以这样做:
#include <iostream>
#include <locale>
class my_num_get : public std::num_get<char> {
protected:
iter_type do_get(iter_type in, iter_type end, std::ios_base& str, std::ios_base::iostate& err, unsigned int& v) const
{
in = std::num_get<char>::do_get(in, end, str, err, v);
if(in != end && !std::isspace(*in, str.getloc()))
err |= std::ios_base::failbit;
return in;
}
};
int main() {
using namespace std;
cin.imbue(std::locale(cin.getloc(), new my_num_get));
cin.exceptions(ios_base::badbit | ios_base::failbit);
try {
unsigned int x;
cin >> x;
} catch(const std::exception &e) {
cerr << e.what() << "n";
}
}
如果您希望这也适用于其他类型,请以相同的方式实现以下内容:
iter_type do_get(iter_type, iter_type, ios_base&, ios_base::iostate&, T& v) const
其中T是bool
、long
、long long
、unsigned short
、unsigned long
、unsigned long long
、float
、double
、long double
和void*
之一。
- 在线程中读取无符号整数时,c++ 位是否以原子方式切换?
- 尝试将字符串从文件读取到无符号字符向量中
- ifstream 尝试读取 9 到 13 之间的无符号字符时非常奇怪的行为
- 从 C++ 中的无符号字符字节流中读取值
- C++ - 将任何文件的字节读取到无符号字符数组中
- 如何在 c++ 中读取/写入无符号数组到 ifstream/ostream?
- std::ifstream 将文件读取为 BYTE(无符号字符)而不是字符
- 用std :: stringstream读取/写作无符号字节
- 如何安全地从流中读取无符号int
- 正在尝试读取4字节无符号整数的二进制文件并转换为伏特
- 如何从文件中读取十六进制并将其存储在无符号字符中
- 如何从无符号变量写入和读取字节
- 使用 ifstream 从C++文件中读取二进制无符号短整型
- 如何从无符号字符(8位)缓冲区读取短整数(16位)
- 向二进制文件写入和读取无符号字符
- C++使用istringstream将int读取为无符号字符
- 如何使用 ifstream 正确从文件中读取无符号的 int 变量
- HDF5在磁盘上将32位无符号int写入64位,并读取32位无信号int
- 在无符号字符数组中读取充满字符串(用换行符分隔)的文件(反之亦然)的最快方法是什么?
- 从文件读取文本到无符号字符数组