C++ 简易解析 csv 文件

字数: 657

在上学期课程设计有一道题就是读写 csv 文件,难倒很大一部分同学,最近开学的实验 0 又需要对文件进行读写,所以写这篇博客作总结。

因为只需要简易解析以达到保存数据的效果,所以也不需要表头。直接按数组索引为行,每个结构体元素为列进行存储。

数据:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
struct Birthday
{
    int year, month, day;
};

struct Student_info
{
  public:
    std::string name;
    std::string gender;
    std::string number;
    Birthday birthday;
    std::string major;
    int admission_score;
};

std::vector<Student> list;

在 C++ 通过 <sstream> 处理字符串流使得字符串解析变得更加容易,通过这一抽象接口读写转换字符串数据轻而易举。

csv 文件分析

csv 文件通过逗号分隔每一列,比如:

1
2
3
小东,,234,20,3,4,123,312
小明,,234,2023,2,2,计算机,213
小马,,12,21,21,21,,12

就是一个 csv 文件的基本内容。

所以只需要读取每一行,按逗号分隔每一数据即可进行解析,读入也是如此。

解析逗号

1
2
3
4
5
6
7
8
9
std::vector<std::string> division(const std::string &line)
{
    std::vector<std::string> column;
    std::string item;
    std::stringstream ss(line);
    while (std::getline(ss, item, ','))
        column.emplace_back(item);
    return column;
}

输入一行数字就能按逗号解析出每一个元素,将其以字符串的形式存储在数组中。
这里通过 stringstream 配合 getline 以指定分界符为 ,

加载 csv 文件

通过 std::ifstream 数据结构读取 csv 文件,通过 getline 逐行读取文件。使用上面的 division 函数解析行,读入对于结构体。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
std::vector<Student> load_from_csv(std::string path)
{
    std::ifstream in(path, std::fstream::out | std::ifstream::in);
    if (!in)
        return std::vector<Student>{};
    std::vector<Student> data;
    std::string line;
    while (std::getline(in, line))
    {
        if (line.empty())
            continue;

        std::vector<std::string> f = division(line);

        Student_info stu;
        stu.name = f[0];
        stu.gender = f[1];
        stu.number = f[2];
        stu.birthday.year = std::stoi(f[3]);
        stu.birthday.month = std::stoi(f[4]);
        stu.birthday.day = std::stoi(f[5]);
        stu.major = f[6];
        stu.admission_score = std::stoi(f[7]);
        Student in(stu);

        data.emplace_back(in);
    }

    return data;
}

写入 csv 文件

写入 csv 文件相对简单,只需要通过 ofstream 覆盖写入即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
void write_to_csv(std::string path)
{
    std::ofstream out(path);
    for (auto &s : list)
    {

        out << s.info.name << "," << s.info.gender << "," << s.info.number << "," << s.info.birthday.year << ","
            << s.info.birthday.month << "," << s.info.birthday.day << "," << s.info.major << ","
            << s.info.admission_score << "\n";
    }
}