C++逐行读取含日期的逗号分隔文件并存入结构体(std::string)
解决CSV读取与结构体存储(使用std::string)的问题
嘿,别担心用std::string存结构体字段的问题——这其实比char[]更省心,还能避免一堆内存管理的坑。我给你梳理一套完整的实现方案,顺便解决优雅遍历字符串字段的困惑:
1. 先定义匹配CSV字段的结构体
直接用std::string对应每个字段就行,不用纠结char[]的长度问题,安全又灵活:
#include <string> #include <vector> #include <fstream> #include <sstream> #include <iostream> #include <iomanip> // 后面解析日期会用到 // 完全对应CSV字段的结构体 struct Employee { std::string firstName; std::string lastName; std::string dob; // 先存字符串,后续可转日期类型 std::string ssn; std::string role; std::string salary; // 也可以直接用double,这里先统一用string示例 std::string zip; std::string phone; };
2. 实现优雅的字符串分割函数(核心!)
要把每一行CSV按逗号拆成单个字段,用std::stringstream配合getline是最优雅的方式,比手动遍历字符高效多了:
// 按指定分隔符分割字符串,返回字段向量 std::vector<std::string> split(const std::string& line, char delimiter) { std::vector<std::string> fields; std::string currentField; std::stringstream lineStream(line); // 逐个读取到分隔符,自动存入向量 while (std::getline(lineStream, currentField, delimiter)) { fields.push_back(currentField); } return fields; }
3. 逐行读取CSV并填充结构体
打开文件后逐行处理,分割字段后直接赋值给结构体成员,还加了格式检查避免出错:
int main() { // 替换成你的CSV文件路径 std::ifstream csvFile("employees.csv"); if (!csvFile.is_open()) { std::cerr << "Error: 无法打开目标CSV文件!" << std::endl; return 1; } std::vector<Employee> employeeList; std::string line; // 如果CSV有表头(比如FirstName,LastName...这一行),先跳过 std::getline(csvFile, line); // 逐行读取处理 while (std::getline(csvFile, line)) { auto fields = split(line, ','); // 检查字段数量是否符合预期(你的CSV是8个字段) if (fields.size() != 8) { std::cerr << "警告:行格式错误,跳过该行 -> " << line << std::endl; continue; } // 填充结构体,直接用std::string赋值就行,完全没障碍 Employee emp; emp.firstName = fields[0]; emp.lastName = fields[1]; emp.dob = fields[2]; emp.ssn = fields[3]; emp.role = fields[4]; emp.salary = fields[5]; emp.zip = fields[6]; emp.phone = fields[7]; employeeList.push_back(emp); } csvFile.close(); // 测试输出,验证存储是否正确 std::cout << "读取到 " << employeeList.size() << " 条员工记录:\n"; for (const auto& emp : employeeList) { std::cout << "- " << emp.firstName << " " << emp.lastName << " | 职位:" << emp.role << " | 薪资:" << emp.salary << "\n"; } // 额外示例:把薪资转成double类型 for (auto& emp : employeeList) { try { double salaryNum = std::stod(emp.salary); std::cout << emp.firstName << " 的薪资数值:" << salaryNum << "\n"; } catch (const std::exception& e) { std::cerr << emp.firstName << " 的薪资格式错误:" << e.what() << "\n"; } } // 额外示例:解析日期为tm结构 for (auto& emp : employeeList) { std::tm dobTm{}; std::istringstream dobStream(emp.dob); dobStream >> std::get_time(&dobTm, "%m/%d/%Y"); if (dobStream.fail()) { std::cerr << emp.firstName << " 的出生日期格式错误:" << emp.dob << "\n"; } else { std::cout << emp.firstName << " 的出生年份:" << dobTm.tm_year + 1900 << "\n"; } } return 0; }
几个关键注意点
- 语法问题:确保你的编译器支持C11及以上(现在基本都支持),范围for循环(
for (const auto& emp : employeeList))、std::stod这些都是C11的特性; - 字段类型转换:如果需要把字符串转成数值/日期类型,用
std::stod/std::get_time就行,记得加异常捕获避免崩溃; - 特殊CSV场景:如果你的CSV里有带引号的字段(比如
"Doe,Jr.",John,...),上面的split函数会把引号里的逗号也当成分隔符,这时候可以考虑用成熟的CSV库(比如FastCSV),或者自己扩展split函数处理引号逻辑。
为什么推荐用std::string而不是char[]?
- 自动管理内存,完全不用操心缓冲区溢出、内存泄漏的问题;
- 支持直接赋值、拼接、比较等操作,代码简洁很多;
- 动态调整长度,不用预先估算每个字段的最大长度。
内容的提问来源于stack exchange,提问作者franny
相关产品推荐
相关产品推荐

