C++读取CSV文件

11

我想使用C ++读取CSV文件,以下是我的代码

 int main(){
 ifstream classFile("class.csv");
 vector<string> classData;

 while (getline(classFile, line,',')) // there is input overload classfile
        {
            classData.push_back(line);  

        }
}

这是我的问题:当读取每一行的最后一列时(因为它没有用逗号分隔),它会读取最后一列数据和下一行的第一个数据。例如,如果我的数据如下:

className,classLocation,Professor c ++,Library,John

那么它会读取成className / classLocation / Professor c ++ / Library / John。

有没有办法将我的最后一列与下一行的第一个列分开呢?谢谢,很抱歉如果它令人困惑。


1
CSV应该在每个记录后面有一个行尾。你的CSV文件每个记录后面都有行尾吗?你可以先获取这一行,然后使用逗号进行分割。 - wendelbsilva
1
你要使用两个分隔符 ,\n 来拆分字符串,但在你的情况下只使用了 ,,因此 \n 成为了字符串的一部分。原文链接:https://dev59.com/EGsz5IYBdhLWcg3w2Llt。 - abasu
可能是将CSV文件的一行拆分为std :: vector?的重复问题。 - Jonathan Mee
4个回答

29

逐行读取文件:

std::string line;
while(std::getline(stream, line)) ...

将每行传递给istringstream并读取字段:

std::istringstream s(line);
std::string field;
while (getline(s, field,',')) ...

免责声明: 这是一个简化版的csv文件解析。


1
肯定是在某种循环中。while循环是一个不错的选择,因为您不一定知道.csv文件的长度,终止条件只会是运行完所有行。 - RangerRick
哇!!它能工作了!!我完全不知道为什么或者怎么做的,但是它能工作了!!XD 谢谢!! - programing_is_hard
我猜应该是istringstream s(line)吧?因为istringstream(line) s不起作用..但非常感谢! - programing_is_hard

5
抱歉,我能在这个线程中插入一些普通的C语言代码吗?
读取csv文件很明显:
#include <stdio.h>


int main()
{
  float f1, f2;

  FILE *fp;
  fp = fopen("file.csv", "r");

  while (fscanf(fp, "%g,%g\n", &f1, &f2) == 2)
    printf("%g\n", f1+f2);
}

肯定可以在C++可用的地方使用。

while中,我们检查fscanf找到了多少个对象:fscanf(fp, "%g,%g\n", &f1, &f2) == 2 -- fscanf返回它找到的对象数量。

希望这能对某些人有所帮助。

(如果有人想看更多关于fscanf和读取文件的信息,请留下评论。)


这个程序不会因为 CSV 格式的微小变化而崩溃吗?例如在逗号后面加上一个空格或使用不同(非 Unix)的换行符。 - j b
2
是的,它肯定会出问题。 此外,在CSV文件中添加空格会增加问题的复杂性,因为程序中字段数量是固定的,而getline函数则不是这种情况。 (尽管通常CSV中字段数量是固定的。) - xealits

2
如果您想在main部分调用一个void函数,请查看以下代码:
void readCSV(const string &strPath2Dataset)
{   
    ifstream csvFile;
    string strPathCSVFile = strPath2Dataset + "/test.csv";
    csvFile.open(strPathCSVFile.c_str());

    if (!csvFile.is_open())
    {
        cout << "Path Wrong!!!!" << endl;
        exit(EXIT_FAILURE);
    }

    vector<long double> timeStampIMU;
    vector<long double> gyro_X;
    vector<long double> gyro_Y;
    vector<long double> gyro_Z;

    vector<long double> acc_X;
    vector<long double> acc_Y;
    vector<long double> acc_Z;

    string line;
    vector <string> vec;
    getline(csvFile, line); // skip the 1st line

    while (getline(csvFile,line))
    {
        if (line.empty()) // skip empty lines:
        {
            //cout << "empty line!" << endl;
            continue;
        }

        istringstream iss(line);
        string lineStream;
        string::size_type sz;

        vector <long double> row;

        while (getline(iss, lineStream, ','))
        {  
            row.push_back(stold(lineStream,&sz)); // convert to double
        }

        timeStampIMU.push_back(row[0]);

        gyro_X.push_back(row[1]);
        gyro_Y.push_back(row[2]);
        gyro_Z.push_back(row[3]);

        acc_X.push_back(row[4]);
        acc_Y.push_back(row[5]);
        acc_Z.push_back(row[6]);
    }

    //cout << "size ts = " << timeStampIMU.size() << endl;
    for (size_t i = 0; i < timeStampIMU.size(); i++)
    {
        cout << "ts_imu = " << setprecision(12) << timeStampIMU[i] << endl;

        cout << "gx = " << setprecision(12) << gyro_X[i] << endl;
        cout << "gy = " << setprecision(12) << gyro_Y[i] << endl;
        cout << "gz = " << setprecision(12) << gyro_Z[i] << endl;

        cout << "ax = " << setprecision(12) << acc_X[i] << endl;
        cout << "ay = " << setprecision(12) << acc_Y[i] << endl;
        cout << "az = " << setprecision(12) << acc_Z[i] << endl;
        cout << "--------------------------------" << endl;
    }
}

我的.csv文件是由IMU传感器提供的数据集,用逗号分隔:

TimeStamp, Gyro_X, Gyro_Y, Gyro_Z, Acc_X, Acc_Y, Acc_Z

0
我找到的所有函数都不支持转义字符,也不考虑除了,(如Unicode字符)以外的任何分隔符,尽管后者在普通字符串中经常使用。因此,这是我自己的DSV读取器版本,支持转义。它可以转义分隔符、转义字符和换行符。您可以通过检查列索引i来手动转换类型。
#include <iostream>
#include <vector>
#include <string>
#include <sstream>

std::vector<std::vector<std::wstring>> DSVToArray(std::wstring text) {
    const wchar_t ch_sep = L'→';
    const wchar_t ch_esc = L'¶';
    const wchar_t ch_newline = L'\n';
    wchar_t pletter = L'\0';
    std::vector<std::wstring> columns = {L""};
    std::vector<std::vector<std::wstring>> rows = {};
    int i = 0;
    int r = 0;
    bool unescaped = true;
    bool is_last = (0 >= text.size() - 1);
    for(std::string::size_type pos = 0; !is_last; ++pos) {
        wchar_t letter = text[pos];
        is_last = (pos >= text.size() - 1);
        if (ch_esc == letter) {
            if (!unescaped && pletter == ch_esc) {
                columns[i] += letter;
            }
            unescaped = !unescaped;
        }
        else if (ch_sep == letter && unescaped) {
            ++i;
            columns.push_back(L"");
            letter = L'\0';
        } else if (ch_newline == letter && unescaped || is_last) {
            if (L'\r' == pletter)
                columns[i] = columns[i].substr(0, columns[i].size() - 1);
            if (ch_newline != letter)
                columns[i] += letter;
            if (columns.size() == 1 && columns[0].size() == 0)
               break;
            rows.push_back({columns});
            columns = {L""};
            i = 0;
            letter = L'\0';
        }
        else {
            columns[i] += letter;
            if (!unescaped)
                unescaped = true;
        }
        pletter = letter;
    }
    return rows;
}

示例用法:

std::wstring join(const std::wstring& sep, const std::vector<std::wstring>& values)
{
    std::wstringstream result;
    for(int i = 0; i < values.size(); i++ )
        result << ( i ? sep : L"" ) << values[i];
    return result.str();
}

int main() {
    std::vector<std::vector<std::wstring>> result = DSVToArray(
        L"a¶→bc→ff¶¶ee\ncc→dd\nee→ff ff"
    );
    for (const auto& columns : result) {
        std::wcout << join(L" -> ", columns) << std::endl;
    }
    std::wcout << std::endl;
    return 0;
}

示例的输出:
a→bc -> ff¶ee
cc -> dd
ee -> ff ff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接