简体   繁体   English

如何一次从文件中读取一个输入,类似于在 C++ 中使用 cin/scanf 从控制台读取输入?

[英]How to read an input from a file one at a time similar to reading input from console using cin/scanf in c++?

I am trying to read input from a file one by one instead of giving it from standard input.我试图从一个文件中一个一个地读取输入,而不是从标准输入中给出它。

What I have, which is currently working!我所拥有的,目前正在运行!

   for(int i = 0; i <CLASS_SIZE; i++)
    {
      for(int j = 0; j <10 ; j++)
        {
            scanf("%d", &grade);
            studentsInClass[i].setGrade(j,grade);
        }  
    }

current input from console is this:控制台的当前输入是这样的:

91 92 85 58 87 75 89 97 79 65
88 72 81 94 90 61 72 75 68 77
75 49 87 79 65 64 62 51 44 70

I want this input to be read directly from a file!我希望直接从文件中读取此输入! So, I tried reading it as a file stream, line by line and then tried to save that line into a vector of strings, so that I can extract the single number per line in an inner loop.因此,我尝试将其作为文件流逐行读取,然后尝试将该行保存到字符串向量中,以便可以在内循环中提取每行的单个数字。

std::ifstream inputfile("input.txt");
std::string line;
std::vector<std::string> v;

for(int i = 0; i <CLASS_SIZE; i++)
{
  for(int j = 0; j <10 ; j++)
    {
        if(inputfile.is_open()){
          while( std::getline(inputfile, line) ){
                std::cout << line << '\n';
                std::istringstream iss(line);
                iss>>v;
                for(std::vector<std::string>::iterator it = v.begin(); it != v.end(); ++it) {
                  studentsInClass[i].setGrade(j, std::stoi(it, nullptr, 2));
             }
          }
        inputfile.close();
        }
    }
}

but getting following error!但出现以下错误! Because I don't know the right way to do it!因为我不知道正确的方法!

error: cannot bind ‘std::basic_istream<char>’ lvalue to ‘std::basic_istream<char>&&’
                     iss>>v;

and below error, because I am trying to convert the string to an integer as my program needs to consume as integer and again I am doing something wrong with the syntax.和以下错误,因为我试图将字符串转换为整数,因为我的程序需要作为整数使用,而我又在语法上做错了。

error: no matching function for call to ‘stoi(std::vector<std::__cxx11::basic_string<char> >::iterator&, std::nullptr_t
, int)’
                       studentsInClass[i].setGrade(j, std::stoi(it, nullptr, 2));

can anyone help to fix this issue?任何人都可以帮助解决这个问题吗?

1) Using scanf() without checking return code is a major problem. 1) 在不检查返回码的情况下使用scanf()是一个主要问题。 If the input does not match your expectations, you're running into undefined behaviour.如果输入不符合您的期望,您就会遇到未定义的行为。

2) Any code that reads from console can read from file by simple use of input redirection. 2) 任何从控制台读取的代码都可以通过简单地使用输入重定向从文件中读取。 ( ./myprog < file.txt ) ( ./myprog < file.txt )

3) Why not first convert from scanf() to std::cin , and then from console to file input? 3)为什么不首先从转换scanf()std::cin然后从控制台文件输入? One step at a time.一步一步来。 (I still think you should leave it to the user to decide whether to input from console or redirect from file. More flexible.) (我仍然认为您应该让用户决定是从控制台输入还是从文件重定向。更灵活。)

4) The equivalent to scanf( "%d", &grade ) is std::cin >> grade . 4) scanf( "%d", &grade ) ) 的等价物是std::cin >> grade No need for that getline() / istringstream stuff, just read one number at a time like you are doing in your currently working code.不需要那种getline() / istringstream东西,就像在当前工作的代码中一样,一次读取一个数字。


As for your errors:至于你的错误:

error: cannot bind ‘std::basic_istream<char>’ lvalue to ‘std::basic_istream<char>&&’
                     iss>>v;

You are trying to read from a stream into a vector ( iss >> v ).您正在尝试从流中读取到向量 ( iss >> v )。 That is not a defined operation.这不是一个定义的操作。 You need to read the values one at a time.您需要一次读取一个值。

error: no matching function for call to ‘stoi(std::vector<std::__cxx11::basic_string<char> >::iterator&, std::nullptr_t
, int)’
                       studentsInClass[i].setGrade(j, std::stoi(it, nullptr, 2));

Your it is an iterator , which needs to be dereferenced to give the value it is referencing ( *it ).您的it是一个迭代器,需要取消引用以提供它所引用的值 ( *it )。 Note what I said previously, though -- your v doesn't get filled as you wanted, see previous error.但是请注意我之前所说的 - 您的v没有按照您的意愿填充,请参阅上一个错误。


Instead of:代替:

 for(std::vector<std::string>::iterator it = v.begin(); it != v.end(); ++it)

Use type deduction (the compiler does know the return type of v.begin() ):使用类型推导(编译器确实知道v.begin()的返回类型):

 for ( auto it = v.begin(); it != v.end(); ++it )

Even better, use a range-for:更好的是,使用 range-for:

 for ( auto & value : v )

for(int i = 0; i <CLASS_SIZE; i++)
{
  for(int j = 0; j <10 ; j++)
    {
        if(inputfile.is_open()){

If inputfile is not open, you can skip the whole loop.如果inputfile未打开,则可以跳过整个循环。 So test before the loop, not inside it.所以循环之前测试,而不是在它里面。

As a first approximation, I'd make the most minimal changes necessary to the code that makes you happy:作为第一个近似值,我会对让您满意的代码进行最少必要的更改:

std::ifstream infile("filename");

for(int i = 0; i <CLASS_SIZE; i++)
{
  for(int j = 0; j <10 ; j++)
    {          
        // scanf("%d", &grade);
        infile >> grade;
        studentsInClass[i].setGrade(j,grade);
    }  
}

Given that you know the exact number of grades for each student, you gain little (if anything) from using getline .鉴于您知道每个学生的确切成绩数,您从使用getline获得的收益很少(如果有的话)。 That would be useful primarily if the input was line-oriented.如果输入是面向行的,这将主要是有用的。 For example, consider an input file like this:例如,考虑这样的输入文件:

91 92 85 58 87 75 89 97 79 65 88 
72 81 94 90 61 72 75 68 77
75 49 87 79 65 64 62 51 44 70

As it stands, you still apparently want this read as 3 students with 10 grades apiece, so the last grade on the first line (the 88 ) belongs to the second student, not the first.就目前而言,您显然仍然希望将其读为 3 个学生,每个学生 10 个成绩,因此第一行的最后一个成绩( 88 )属于第二个学生,而不是第一个。

Using getline and then parsing each line individually would make sense if you wanted this input data interpreted as the first student having 11 grades, and the second student 9 grades (and the third 10 grades).如果您希望将此输入数据解释为第一个学生有 11 个成绩,第二个学生有 9 个成绩(以及第三个学生有 10 个成绩),那么使用getline然后单独解析每一行是有意义的。


That covers the question you asked, but I'm still not particularly happy about the code.这涵盖了您提出的问题,但我对代码仍然不是特别满意。 Personally, I'd prefer to write a student class that knew how to read its own data from a stream:就个人而言,我更愿意编写一个学生类,它知道如何从流中读取自己的数据:

class student { 
    std::vector<int> grades;
public:

   // other stuff, of course.

   friend std::istream &operator>>(std::istream &is, student &s) {
       int grade;
       for (int i=0; i<10; i++) {
           is >> grade;
           s.grades.push_back(grade);
       }
       return is;
    }
};

Then when we want to read data for multiple students, we'd do something like this:然后当我们想要读取多个学生的数据时,我们会做这样的事情:

std::vector<students> the_class;
std::ifstream infile("grades.txt");

for (int i=0; i<CLASS_SIZE; i++) {
    student s;

    // use `operator>>` above to read all 10 grades for one student.
    infile >> s;
    the_class.push_back(s);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM