C ++ - 无法将CSV解析为我的结构

时间:2016-07-15 18:21:50

标签: c++ csv parsing struct

我的CSV格式如下:

date,fruit,quantity1,quantity2,quantity3
2016-07-14,banana,3,20,6
2016-07-14,banana,3,50,15
2016-07-14,banana,0,25,15
2016-07-14,banana,3,25,6
2016-07-14,apple,3,10,20.5
2016-07-14,apple,0,30,5
2016-07-14,apple,0,5,30
2016-07-14,peach,3,10,30.2
2016-07-14,peach,3,40,4
2016-07-14,peach,3,10,12
2016-07-14,peach,0,10,8
2016-07-14,peach,3,200,3

我想解析这个文件并将其存储在一个struct中。但我收到堆栈溢出错误。它究竟在哪里失败?是因为结构中的数据类型发生了冲突吗?一些数据类型是浮点数,我正在尝试使用getline和一个临时字符串变量来存储信息。

以下是完整的代码:

#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

using namespace std;

struct FruitInventory
{
    string date;
    string fruit;
    float quantity1;
    float quantity2;
    float quantity3;
};

int main()
{
    ifstream myfile;
    myfile.open("fruit_inventory.csv", ios::in);

    string line;

    FruitInventory todaysFruitSupply[15000];

    int i = 0;

    int lineCount = 0;

    while (myfile.good())
    {
        getline(myfile, line);

        stringstream mystream(line);

        string temp;

        if (i > 0) //ignore header line
        {
            getline(mystream, todaysFruitSupply[i].date, ',');
            getline(mystream, todaysFruitSupply[i].fruit, ',');
            getline(mystream, temp, ',');
            todaysFruitSupply[i].quantity1 = stof(temp);
            getline(mystream, temp, ',');
            todaysFruitSupply[i].quantity2 = stof(temp);
            getline(mystream, temp, ',');
            todaysFruitSupply[i].quantity3 = stof(temp);
        }

        i++;
        lineCount++;
    }

    myfile.close();

    system("pause");

    return 0;
}
编辑:它在文件的最后一行打破,因为有一个换行符。删除后,它现在完全执行。我怎样才能确保将来能够正确处理?

2 个答案:

答案 0 :(得分:2)

这是一个要分配为局部变量的大对象:

FruitInventory todaysFruitSupply[15000];

这显然是堆栈溢出的原因。正如上面的评论所说,您应该考虑一个动态数据结构,例如std::vector,它将根据需要增长并自动管理其内存。

std::vector<FruitInventory> todaysFruitSupply;
  

它打破了文件的最后一行,因为有一个换行符。删除后,它现在完全执行。我怎样才能确保将来能够正确处理?

当你读一行时,你应该检查它是否为空:

while (myfile.good())
{
    getline(myfile, line);
    if (line.empty())
        break;

或者更好的是,不要继续使用good(),而是测试输入操作的结果:

while (getline(myfile, line) && !line.empty())
{

整个事情看起来像:

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

using namespace std;

struct FruitInventory
{
    string date;
    string fruit;
    float quantity1;
    float quantity2;
    float quantity3;
};

int main()
{
    ifstream myfile;
    myfile.open("fruit_inventory.csv", ios::in);

    string line;

    std::vector<FruitInventory> todaysFruitSupply;

    int lineCount = 0;
    getline(myfile, line); // ignore header line

    FruitInventory inv;

    while (getline(myfile, line) && !line.empty())
    {
        stringstream mystream(line);

        string temp;
        getline(mystream, inv.date, ',');
        getline(mystream, inv.fruit, ',');
        getline(mystream, temp, ',');
        inv.quantity1 = stof(temp);
        getline(mystream, temp, ',');
        inv.quantity2 = stof(temp);
        getline(mystream, temp, ',');
        inv.quantity3 = stof(temp);
        if (!mystream)
            break; // something went wrong reading the line

        todaysFruitSupply.push_back(inv);
        lineCount++;
    }
}

答案 1 :(得分:-3)

微小结构的15K阵列无法导致堆栈溢出。如果最初存在堆栈溢出,则从数据文件中删除一个空行都不会修复它。问题不同。

getline(myfile, line);

//After the above line in your code, you must add:

if ( myfile.eof() ) 
        break;

这是因为如果文件处于良好状态,则在进行循环检查时,在读取之前而不是在尝试从中读取之后。或者,您可以加入getline(..)&amp;&amp;文件对象健康检查:

while (getline(myfile, line) && myfile.good() )

这两个修复都是等效的(对于这个问题,虽然从技术上来说它们是不同的)并且在当前程序和数据中根本没有区别,但随着程序员的成熟,他们将选择后者。如果此更改适合您,请在下面添加评论。

此外,您需要检查是否存在非空字符串以及使用不会导致异常的字符串标记生成器。学习try / catch时可以使用IOException处理程序。