理解用c ++读取txt文件

时间:2014-09-22 16:41:50

标签: c++ ifstream

我试图理解在c ++中阅读不同的txt文件格式

我目前正在尝试阅读格式如下的文件

val1 val2 val3
val1 val2 val3
val1 val2 val3

当我读入文件然后cout其内容时,我只得到第一行,然后是最后的0 0

我想将每个值保存到结构中自己的变量中。

我这样做,

struct Input{
    std::string group;
    float total_pay;
    unsigned int quantity;

    Input(std::string const& groupIn, float const& total_payIn, unsigned int const& quantityIn):
    group(groupIn),
    total_pay(total_payIn),
    quantity(quantityIn)
    {}
};

int main(){

    std::ifstream infile("input.txt");
    std::vector<Input> data;

    std::string group;
    std::string total_pay;
    std::string quantity;

    std::getline(infile,group);
    std::getline(infile,total_pay);
    std::getline(infile,quantity);

    while(infile) {
        data.push_back(Input(group,atof(total_pay.c_str()),atoi(quantity.c_str())));

        std::getline(infile,group);
        std::getline(infile,total_pay);
        std::getline(infile,quantity);
    }


    //output
    for(Input values : data) {
        std::cout << values.group << " " << values.total_pay << " " << values.quantity << '\n';
    }

    return 0;
}

以我指定的格式读取此文件的正确方法是什么?我是否需要指定在第三个值之后转到下一行?

或者这应该取每个值并将它们放入正确的变量?

std::getline(infile,group);
std::getline(infile,total_pay);
std::getline(infile,quantity);

2 个答案:

答案 0 :(得分:2)

您的输入处理存在许多问题。您在不需要的地方普遍使用std::getline无济于事。

简而言之,输入的每行验证通常使用类似于以下的模型完成。请注意,这要求类提供默认构造函数。我们使用输入字符串流来处理来自输入文件的每行输入的单个项。如果某些每行最多一个,我们可以放弃每行处理,但它可能是错误的地方,所以比抱歉更安全。这里介绍的口头禅通常用于从格式化输入文件中读取对象流时的每行输入验证,每行一个项目。

以下代码定义了具有一些额外部分的结构,包括提供输入和输出流插入运算符。结果使main() 中的代码更易于管理。

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

struct Input
{
    // friends not needed if the members are public, but provided here
    //  in case you ever do make them protected or private (which you should)
    friend std::istream& operator >>(std::istream& inp, Input& item);
    friend std::ostream& operator <<(std::ostream& outp, Input const& item);

    std::string group;
    float total_pay;
    unsigned int quantity;

    // default constructor. sets up zero-elements
    Input() : total_pay(), quantity()
    {
    }

    Input(std::string groupIn, float total_payIn, unsigned int quantityIn)
        : group(std::move(groupIn))
        , total_pay(total_payIn)
        , quantity(quantityIn)
    {
    }

    // you really should be using these for accessors
    std::string const& getGroup() const { return group; }
    float getTotalPay() const { return total_pay; }
    unsigned int getQuantity() const { return quantity; }
};

// global free function for extracting an Input item from an input stream
std::istream& operator >>(std::istream& inp, Input& item)
{
    return (inp >> item.group >> item.total_pay >> item.quantity);
}

// global operator for inserting to a stream
std::ostream& operator <<(std::ostream& outp, Input const& item)
{
    outp << item.getGroup() << ' '
         << item.getTotalPay() << ' '
         << item.getQuantity();
    return outp;
}

int main()
{
    std::ifstream infile("input.txt");
    if (!infile)
    {
        std::cerr << "Failed to open input file" << '\n';
        exit(EXIT_FAILURE);
    }

    // one line per item enforced.
    std::vector<Input> data;
    std::string line;
    while (std::getline(infile, line))
    {
        std::istringstream iss(line);
        Input inp;
        if (iss >> inp) // calls our extaction operator >>
            data.emplace_back(inp);
        else
            std::cerr << "Invalid input line: " << line << '\n';
    }

    // dump all of them to stdout. calls our insertion operator <<
    std::copy(data.begin(), data.end(),
              std::ostream_iterator<Input>(std::cout,"\n"));
    return 0;
}

如果输入格式正确,则值如下:

group total quantity
group total quantity

将成功解析。相反,如果发生这种情况:

group total quantity
group quantity
group total quantity
total quantity

第二和第四项的提取将失败,并将在std::cerr上发出适当的警告。这就是使用std::istringstream中间流对象包装提取每个项目的单行的原因。

祝你好运,我希望它可以帮助你。

答案 1 :(得分:0)

检查此解决方案

没有错误检查,但转换为类型

#include<iostream>
#include<sstream>
using namespace std;
int main()
{
    string line="v1 2.2 3";//lets say you read a line to this var...
    string group;
    float total_pay;
    unsigned int quantity;
    //we split the line to the 3 fields
    istringstream s(line);
    s>>group>>total_pay>>quantity;
    //print for test
    cout<<group<<endl<<total_pay<<endl<<quantity<<endl;
    return 0;
}