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

C++ - Failing to parse CSV into my struct

本文关键字:我的 结构 CSV C++      更新时间:2023-10-16

我有一个格式如下的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

我想解析此文件并将其存储在结构中。 但是我遇到堆栈溢出错误。 它到底在哪里失败? 是因为结构中的数据类型冲突吗? 一些数据类型是浮点数,我正在尝试使用 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;
}

编辑:它在文件的最后一行中断,因为有一个换行符。 删除后,它现在完全执行。 我如何确保它将来可以正确处理这个问题?

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

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++;
    }
}

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

getline(myfile, line);
//After the above line in your code, you must add:
if ( myfile.eof() ) 
        break;

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

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

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

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