如何使用ifstream从文件正确读取未签名的int变量? [英] How to read unsigned int variables from file correctly, using ifstream?

查看:87
本文介绍了如何使用ifstream从文件正确读取未签名的int变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的代码从文本文件Input_File_Name中读取无符号的int变量.

My code reads unsigned int variables from the text file 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;
}

效果很好. 但是当我用错误的数据填充文本文件时

It works excellent. But when I fill text file with a wrong data

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异常?

Why doesn't this line input_stream>>Row_Count; throw exception? As I understood, input_stream considers any non-numeric symbol as delimiter, and on the next step it tries to read "abcd". Is it so? How to set a Space-symbol as delimiter to throw an ios::failure exception from this line of code input_stream>>Row_Count; while reading "33abcd4"?

推荐答案

如果流可以读取任何整数值,则正常提取整数值将成功.也就是说,如果至少有一个数字(可选)后跟任何数字,则整数读取成功.正常的提取操作不要尝试阅读更多内容,尤其是不要尝试查找下一个空格.

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:

  1. 创建一个简单的操纵器,检查流是否在空白字符上.但是,这意味着您将使用类似in >> value >> is_space的值来读取值.
  2. 创建一个自定义的std::num_get<char>构面,将其安装到std::locale中,并将imbue()std::locale安装到您的流中.它涉及更多,但不需要更改读取整数的方式.
  1. Create a simple manipulator which checks for the stream being on a whitespace character. This, however, means that you would read your values using something like in >> value >> is_space.
  2. Create a custom std::num_get<char> facet, install it into a std::locale, and imbue() this std::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:

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>构面的替代品:

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 with unsigned int: to do it for other integral types it is necessary to override more functions. So, here is a replacement for the std::num_get<char> facet:

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中设置错误状态),覆盖将检查是否存在另一个可用字符,如果是,则检查是否为空格,如果不是,则设置在错误结果err中.

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 a std::ios_base::failbit in the error result err.

剩下的是设置流以在std::locale中使用此特定方面,并将新的std::locale挂接到流中:

What remains is to set up the stream to use this particular facet in a std::locale and hook the new std::locale into a stream:

std::locale loc(std::locale(), new num_get);
in.imbue(loc);

std::locale和它的构面是内部引用计数,即,您不应该跟踪指向构面的指针,也不需要保持std::locale左右.如果imbue()创建的std::locale似乎很麻烦,或者您想在所有地方使用此修改后的逻辑,则可以设置全局std::locale,该全局<​​c6>用于初始化任何新创建的流以使用自定义std::num_get<char>方面.

The std::locales 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 the std::locale around either. If it seems to be to cumbersome to imbue() the created std::locale or you want to use this modified logic everywhere, you can set the global std::locale which is used to initialize any newly created stream to use the custom std::num_get<char> facet.

这篇关于如何使用ifstream从文件正确读取未签名的int变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆