实用--小巧的CSV文件解析读取封装
背景
CSV(Comma-Separated Values)文件格式是一种场景的文本格式化文件, 简单轻量, 一般的第一列可以放置列标题, 以下放置内容, 如下:
ID,NAME,AGE,HEIGHT,WEIGHT
1,李雷,18,1.73,131
2,刘雷,18,1.81,150
本文提供一个小巧的解析读取csv文件的封装类实现, 并提供全部代码及测试代码资源下载
CSV文件解析封装类源码资源-C++文档类资源-CSDN下载
实现思路
1.解析头信息
2.读取行信息,并按照头信息顺序建立一个kv结构
3.对外提供简洁的操作接口, 支持kv方式getvalue,并支持转换各种数据类型
代码
类定义
class CSVFile
{
public:
CSVFile(const std::string& filePath);
~CSVFile();
bool Open();
int GetFieldsCount() const;
bool Next();
void Close();
int GetInteger(const std::string& key);
unsigned int GetUInt(const std::string& key);
double GetDouble(const std::string& key);
std::string GetValue(const std::string& key);
private:
std::vector<std::string> ReadNextLine();
bool ParseHeader();
std::string filePath_;
std::fstream fs_;
std::vector<std::string> headers_;
std::map<std::string, std::string> lineFields_;
int length_;
std::unique_ptr<char[]> fileBuffer_;
int filePos_;
};
实现代码:
CSVFile::CSVFile(const std::string& filePath) : filePath_(filePath)
{
length_ = 0;
filePos_ = 0;
}
CSVFile::~CSVFile()
{
if(fs_.is_open())
{
fs_.close();
}
}
bool CSVFile::Open()
{
fs_.open(filePath_.c_str());
if(!fs_.is_open())
{
return false;
}
fs_.seekg(0, fs_.end);
length_ = fs_.tellg();
fs_.seekg(0, fs_.beg);
fileBuffer_.reset(new char[length_ + 1]);
fileBuffer_[length_] = 0;
fs_.read(fileBuffer_.get(), length_);
return ParseHeader();
}
int CSVFile::GetFieldsCount() const
{
return (int)headers_.size();
}
vector<string> CSVFile::ReadNextLine()
{
vector<string> result;
string fieldValue;
while(filePos_ < length_)
{
if(fileBuffer_[filePos_] == ',')
{
result.push_back(fieldValue);
fieldValue.clear();
++filePos_;
continue;
}
else if(fileBuffer_[filePos_] == '\r')
{
++filePos_;
continue;
}
else if(fileBuffer_[filePos_] == '\n')
{
result.push_back(fieldValue);
fieldValue.clear();
++filePos_;
break;
}
else
{
fieldValue += fileBuffer_[filePos_];
}
++filePos_;
}
if(!fieldValue.empty())
{
result.push_back(fieldValue);
}
return std::move(result);
}
bool CSVFile::Next()
{
lineFields_.clear();
vector<string> fieldValues = ReadNextLine();
if(fieldValues.size() != headers_.size())
{
return false;
}
for(int i = 0; i < headers_.size(); ++i)
{
lineFields_.insert(make_pair(headers_[i], fieldValues[i]));
}
return lineFields_.size() == headers_.size();
}
void CSVFile::Close()
{
fs_.close();
}
int CSVFile::GetInteger(const std::string& key)
{
auto it = lineFields_.find(key);
if(it == lineFields_.end())
{
return 0;
}
return atoi(it->second.c_str());
}
unsigned int CSVFile::GetUInt(const std::string& key)
{
auto it = lineFields_.find(key);
if(it == lineFields_.end())
{
return 0;
}
return atoi(it->second.c_str());
}
double CSVFile::GetDouble(const std::string& key)
{
auto it = lineFields_.find(key);
if(it == lineFields_.end())
{
return 0;
}
return strtod(it->second.c_str(), nullptr);
}
std::string CSVFile::GetValue(const std::string& key)
{
auto it = lineFields_.find(key);
if(it == lineFields_.end())
{
return "";
}
return it->second.c_str();
}
bool CSVFile::ParseHeader()
{
headers_ = ReadNextLine();
return !headers_.empty();
}
测试代码示例:
TEST_F(CSVFileTest, TestSimple)
{
CSVFile csvFile("./src/unittest/a.csv");
if(!csvFile.Open())
{
GTEST_FAIL();
return;
}
cout << "FieldsCount:" << csvFile.GetFieldsCount() << endl;
EXPECT_TRUE(csvFile.GetFieldsCount() == 5);
vector<Person> personList;
while(csvFile.Next())
{
Person p;
p.id = csvFile.GetUInt("ID");
p.name = csvFile.GetValue("NAME");
p.age = csvFile.GetUInt("AGE");
p.height = csvFile.GetDouble("HEIGHT");
p.weight = csvFile.GetDouble("WEIGHT");
p.Print();
personList.push_back(p);
}
if(personList.size() != 2)
{
GTEST_FAIL();
return;
}
EXPECT_TRUE(personList[1].height == 1.81);
}
运行效果:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?