【问题标题】:How can I use to the stream extraction operator to read a file assuming that only the last line will have errors of not containing 3 values假设只有最后一行会出现不包含 3 个值的错误,我如何使用流提取运算符读取文件
【发布时间】:2025-12-25 01:05:13
【问题描述】:

正在阅读的文本文件

1 1 1
1.2 -2.3 0.4
-2 -3 -4
+0 -2 8.85
2.345

我的代码:

#include <iostream>
#include <fstream>

using namespace std;

double readFile(ifstream &myfile, double &a, double &b, double &c);
int main()
{
    int counter = 0;
    double a, b, c;
    string line, inputFile, outputFile;

    cout << "Enter the name of your input file: ";
    cin >> inputFile;

    cout << "Enter the name of your output file: ";
    cin >> outputFile;

    ifstream myfile(inputFile);
    if(myfile.is_open())
    {
        while(!myfile.eof())
        {
            readFile(myfile, a, b, c, counter);
            calculations(a, b, c);
        }


    }
    else cout << "unable to open file";
    return 0;
}

double readFile(ifstream &myfile, double &a, double &b, double &c)
{
    //Reads one line of the file
    myfile >> a >> b >> c;
    cout << a << " " << b << " " << c << endl;

}

我想要做的是,如果最后一行没有 3 个值,我希望有某种停止代码,如果它的值少于 3 个,它将停止处理,并且前一行的剩余值不会是分配

【问题讨论】:

标签: c++


【解决方案1】:

您最大的问题是&gt;&gt; 会跳过前导空格,因此它不会区分' '(空格)或'\n'——它只是空格。要正确处理它,您需要将每一行读入一个std::string,然后从该行创建一个std::stringstream

然后从std::stringstream&gt;&gt; 中读取您的三个double 值。这样一来,您读取的 double 值不会超过该行中的值。否则,如果您只是尝试使用 &gt;&gt;,您会很高兴地从一行读取 2 个 double 值,从下一行读取第三个值,而没有任何迹象表明会发生这种情况。

您接下来需要您的函数来指示从该行读取三个double 值的成功/失败。 bool 的返回类型就是您所需要的。如果您读取了三个有效的double 值,请返回true 并执行您的calculations(),否则,如果您返回false,请停止尝试从文件中读取。

一个简短的例子是:

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

bool read3doubles (std::ifstream& f, double& a, double& b, double& c)
{
    std::string line {};                /* std::string to hold line */
    
    if (getline (f, line)) {            /* if line read from file */
        std::stringstream ss(line);     /* create stringstream from line */
        if (ss >> a >> b >> c)          /* if 3 doubles read from line */
            return true;                /* return true */
    }
    
    return false;   /* otherwise, return false */
}

void calculations (double& a, double& b, double& c)
{
    std::cout << a << "  " << b << "  " << c << '\n';
}

int main (int argc, char **argv) {

    if (argc < 2) { /* validate at least 1 argument given */
        std::cerr << "error: insufficient number of arguments.\n"
                    "usage: " << argv[0] << " <filename>\n";
        return 1;
    }

    std::ifstream f (argv[1]);          /* open file-stream with 1st argument */
    double a, b, c;
    
    if (!f.good()) {    /* validate file open for reading */
        std::cerr << "errro: file open failed '" << argv[1] << "'.\n";
        return 1;
    }

    while (read3doubles(f, a, b, c))    /* while 3 doubles read from file */
        calculations (a, b, c);         /* do your calculation */
    
}

注意:calculations()函数在读取成功时只输出三个双精度)

使用/输出示例

使用您在文件 dat/3doubles.txt 中的输入,您将拥有:

$ ./bin/read3doubles dat/3doubles.txt
1  1  1
1.2  -2.3  0.4
-2  -3  -4
0  -2  8.85

如果您还有其他问题,请告诉我。

【讨论】:

  • 感谢您解释我的代码出了什么问题以及如何改进它
【解决方案2】:

std::istreamoperator&gt;&gt; 无法从流中提取值时设置failbit。在您的代码中,failbit如果解析3个可以解析为double的值失败,将被设置,您可以查询failbit是否由std::failbit()设置。

double readFile(ifstream &myfile, double &a, double &b, double &c)
{
    myfile >> a >> b >> c;

    if(myfile.fail())
    {
        // failbit is set if one of a, b or c is not parsed successfully.
        // do some stop code here.
    }

    cout << a << " " << b << " " << c << endl;

}

请记住,如果设置了failbitstd::istream 不会对进一步的操作做任何事情。如果您需要继续从流中读取,您应该调用std::clear() 清除failbit

【讨论】:

    【解决方案3】:

    我添加了一个不同的函数,它按空格分割一行并将它们转换为数字。您的主要功能基本上不受影响。虽然我做了一些更改,比如添加了std::vector,但提前返回以删除一些嵌套。

    另外,我将主要的while 条件从eof 更改为std::getline

    • std::string_view 上的操作非常便宜。

    • 这样您可以检查每一行读取的值的数量始终是您需要的。

    • 对于错误的输入,如果一行/单词不是数字,您可以通过在异常捕获器中打印它来轻松调试。

    #include <iostream>
    #include <fstream>
    #include <vector>
    using namespace std;
    
    void read_values(std::string_view line, std::vector<double> &values);
    void calculations(int, int, int);
    int main()
    {
      string inputFile, outputFile;
    
      cout << "Enter the name of your input file: ";
      cin >> inputFile;
    
      cout << "Enter the name of your output file: ";
      cin >> outputFile;
    
      ifstream myfile(inputFile);
      if (!myfile.is_open()) {
        cout << "unable to open file";
        return -1;
      }
    
      std::string line;
      std::vector<double> values;
      while (std::getline(myfile, line, '\n')) {
        read_values(line, values);
        std::cout << values.size();
      }
      return 0;
    }
    
    void read_values(std::string_view line, std::vector<double> &values)
    {
      while (!line.empty()) {
        const std::string_view::size_type pos_space{line.find(' ')};
        try {
          values.push_back(std::stod(std::string(line.substr(0, pos_space))));
        }
        catch (const std::invalid_argument &ex) {
          std::cout << ex.what() << std::endl;
          return;
        }
        line.remove_prefix(pos_space + 1);
      }
    }
    
    

    【讨论】:

      最近更新 更多