在C++开发中,csv文件作为一种轻量级的表格数据存储格式被广泛使用,很多场景下需要程序读取或生成csv文件。使用标准库中的fstream完成文件读写,配合合适的字符串分割逻辑,就能高效实现csv文件的解析与处理。

fstream基础用法
fstream是C++标准库中用于文件操作的类,包含ifstream(输入文件流)和ofstream(输出文件流),可以分别用于读取和写入文件。处理csv文件时,通常先用ifstream打开目标csv文件,逐行读取内容后再进行分割处理。
打开文件时需要指定文件路径和打开模式,常用的模式有ios::in(读模式)、ios::out(写模式),如果不指定模式,fstream会默认以读写模式打开。
读取csv文件示例
以下代码演示了使用ifstream打开csv文件并逐行读取的基础逻辑:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
// 创建输入文件流对象,打开当前目录下的test.csv文件
ifstream inFile("test.csv", ios::in);
// 判断文件是否成功打开
if (!inFile.is_open()) {
cout << "文件打开失败" << endl;
return -1;
}
string line;
// 逐行读取文件内容
while (getline(inFile, line)) {
cout << "读取到行内容:" << line << endl;
}
// 关闭文件流
inFile.close();
return 0;
}
字符串分割方法实现
读取到csv文件的单行内容后,需要按照逗号分割字段,但csv格式可能存在特殊情况:比如字段内容本身包含逗号,会用双引号包裹该字段,此时不能简单按逗号分割。下面介绍两种常用的分割方法。
基础逗号分割方法
这种方法适用于字段中不包含逗号和双引号的简单csv场景,直接遍历字符串,遇到逗号就截取一段字段。
#include <vector>
#include <string>
using namespace std;
// 基础字符串分割函数,按逗号分割字符串
vector<string> split_csv_simple(const string& str) {
vector<string> result;
string temp;
for (char c : str) {
if (c == ',') {
// 遇到逗号,将临时存储的内容加入结果集
result.push_back(temp);
temp.clear();
} else {
temp += c;
}
}
// 加入最后一个字段
result.push_back(temp);
return result;
}
支持带引号字段的分割方法
当csv字段包含逗号且被双引号包裹时,需要忽略引号内的逗号,同时处理字段首尾的双引号。实现逻辑是遍历字符串时记录是否在引号内部,在引号内时遇到逗号不分割。
#include <vector>
#include <string>
using namespace std;
// 支持带引号字段的csv字符串分割函数
vector<string> split_csv(const string& str) {
vector<string> result;
string temp;
bool in_quotes = false; // 标记是否在双引号内部
for (size_t i = 0; i < str.size(); ++i) {
char c = str[i];
if (c == '"') {
// 遇到双引号,切换引号状态
in_quotes = !in_quotes;
} else if (c == ',' && !in_quotes) {
// 不在引号内遇到逗号,完成一个字段的截取
result.push_back(temp);
temp.clear();
} else {
temp += c;
}
}
// 加入最后一个字段,同时去除字段首尾的双引号
if (!temp.empty() && temp[0] == '"' && temp[temp.size()-1] == '"') {
temp = temp.substr(1, temp.size()-2);
}
result.push_back(temp);
return result;
}
完整csv读取解析示例
结合fstream读取和字符串分割方法,就可以实现完整的csv文件解析功能,以下代码可以读取包含带引号字段的csv文件并输出所有字段内容。
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
// 支持带引号字段的csv字符串分割函数
vector<string> split_csv(const string& str) {
vector<string> result;
string temp;
bool in_quotes = false;
for (size_t i = 0; i < str.size(); ++i) {
char c = str[i];
if (c == '"') {
in_quotes = !in_quotes;
} else if (c == ',' && !in_quotes) {
result.push_back(temp);
temp.clear();
} else {
temp += c;
}
}
if (!temp.empty() && temp[0] == '"' && temp[temp.size()-1] == '"') {
temp = temp.substr(1, temp.size()-2);
}
result.push_back(temp);
return result;
}
int main() {
ifstream inFile("test.csv", ios::in);
if (!inFile.is_open()) {
cout << "文件打开失败" << endl;
return -1;
}
string line;
int row = 0;
while (getline(inFile, line)) {
cout << "第" << row << "行内容:" << endl;
vector<string> fields = split_csv(line);
for (size_t i = 0; i < fields.size(); ++i) {
cout << "字段" << i << ":" << fields[i] << endl;
}
row++;
}
inFile.close();
return 0;
}
csv文件写入方法
除了读取csv文件,有时也需要生成csv文件,使用ofstream即可实现。写入时如果字段包含逗号或双引号,需要将字段用双引号包裹,并且字段内的双引号需要转义为两个双引号。
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
// 处理字段内容,包含逗号或双引号时添加转义
string process_field(const string& field) {
bool need_quote = false;
string processed;
for (char c : field) {
if (c == '"') {
// 双引号转义为两个双引号
processed += '"';
need_quote = true;
} else if (c == ',') {
need_quote = true;
}
processed += c;
}
if (need_quote) {
return '"' + processed + '"';
}
return processed;
}
int main() {
// 创建输出文件流,写入test_output.csv
ofstream outFile("test_output.csv", ios::out);
if (!outFile.is_open()) {
cout << "文件创建失败" << endl;
return -1;
}
// 准备要写入的csv数据
vector<vector<string>> data = {
{"姓名", "年龄", "简介"},
{"张三", "25", "热爱编程,擅长C++"},
{"李四", "30", "喜欢"旅行",去过很多城市"}
};
// 逐行写入数据
for (const auto& row : data) {
string line;
for (size_t i = 0; i < row.size(); ++i) {
if (i > 0) {
line += ',';
}
line += process_field(row[i]);
}
outFile << line << endl;
}
outFile.close();
cout << "csv文件写入完成" << endl;
return 0;
}