实用--小巧的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);
}

运行效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值