项目源代码:https://github.com/OpenMiniServer/opencsv
使用C++分析大数据的时候,数据按CSV格式导出,可以用Excel分析数据。
OpenCSV非常易用和简单。
测试例子:
#include <assert.h>
#include "opencsv.h"
int main()
{
std::string buffer1;
std::string buffer2;
//生成CSV数据
{
OpenCSV csv = { "ID", "name", "salary" };
csv = { "1", "Jack", "100000" };
csv = { "2", "Tom", "80000" };
csv = { std::to_string(3), "Lucy", "50000" };
csv >> buffer1;
}
buffer2 = "ID,name,salary\n"
"1,Jack,100000\n"
"2,Tom,80000\n"
"3,Lucy,50000\n";
assert(buffer1 == buffer2);
//解析CSV数据
{
OpenCSV csv;
csv << buffer2;
buffer1 = "ID,name,salary\n";
for (size_t i = 1; i < csv.size(); ++i)
{
auto& line = csv[i];
buffer1.append(line["ID"] + "," + line["name"] + "," + line["salary"] + "\n");
}
}
assert(buffer1 == buffer2);
std::string filePath = "./test.csv";
//生成CSV文件
{
OpenCSV csv;
csv << buffer2;
assert(csv[0][0] == "ID");
assert(csv[0][2] == "salary");
csv[1]["salary"] = std::to_string(10000);
csv[2]["salary"] = "8000";
csv[3]["salary"] = "5000";
csv >> filePath; //自动判断是否是路径
}
buffer2 = "ID,name,salary\n"
"1,Jack,10000\n"
"2,Tom,8000\n"
"3,Lucy,5000\n";
//加载CSV文件
{
OpenCSV csv;
csv << filePath; //自动判断是否是路径
buffer1.clear();
csv >> buffer1;
}
assert(buffer1 == buffer2);
return 0;
}
跨平台支持:
Windows、linux
源文件列表:
src/opencsv.h
src/opencsv.cpp
运行测试例子
cd ./opencsv
mkdir build
cd build
cmake ..
make
./test
源文件:
src/opencsv.h
/***************************************************************************
* Copyright (C) 2023-, openlinyou, <linyouhappy@outlook.com>
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
***************************************************************************/
#ifndef HEADER_OPEN_CSV_H
#define HEADER_OPEN_CSV_H
#include <string>
#include <vector>
class OpenCSV
{
typedef std::vector<std::string> Line;
class CSVLine
{
Line line_;
OpenCSV* csv_;
CSVLine()
:csv_(0) {}
friend class OpenCSV;
public:
CSVLine(OpenCSV* csv)
:csv_(csv){}
CSVLine(const CSVLine& csvline)
{
csv_ = csvline.csv_;
if (!csvline.line_.empty())
{
line_ = csvline.line_;
}
}
inline size_t size() { return line_.size(); }
inline bool empty() { return line_.empty(); }
inline Line& line() { return line_; }
std::string& operator[](size_t idx);
std::string& operator[](const std::string& key);
};
typedef const std::initializer_list<std::string> List;
std::vector<CSVLine> lines_;
std::string emptyStr_;
friend class CSVLine;
public:
OpenCSV() {}
OpenCSV(List& list);
void operator=(List& list);
//OpenCSV(OpenCSV& csv);
//void operator=(OpenCSV& csv);
inline bool empty() { return lines_.empty(); }
inline size_t size() { return lines_.size(); }
CSVLine& operator[](size_t idx);
void operator>>(std::string& output);
void operator<<(const std::string& output);
inline std::vector<CSVLine>& lines() { return lines_; }
};
#endif /* HEADER_OPEN_CSV_H */
src/opencsv.cpp
#include "opencsv.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <string>
#include <vector>
static bool CheckFilePath(const std::string& filePath);
static int64_t ReadFile(const std::string& filePath, std::string& buffer, const char* m);
static int64_t WriteFile(const std::string& filePath, std::string& buffer, const char* m);
std::string& OpenCSV::CSVLine::operator[](size_t idx)
{
if (idx >= line_.size())
{
line_.resize(idx + 1);
}
return line_[idx];
}
std::string& OpenCSV::CSVLine::operator[](const std::string& key)
{
OpenCSV* csv = dynamic_cast<OpenCSV*>(csv_);
if (csv == 0 || csv->lines_.empty())
{
static std::string emptyStr;
assert(false);
return emptyStr;
}
CSVLine& keyLine = csv->lines_[0];
size_t idx = 0;
for (; idx < keyLine.size(); ++idx)
{
if (keyLine[idx] == key) break;
}
if (idx < keyLine.size())
{
return line_[idx];
}
assert(false);
csv->emptyStr_.clear();
return csv->emptyStr_;
}
OpenCSV::OpenCSV(List& list)
{
if (list.size() > 0)
{
lines_.resize(lines_.size() + 1, CSVLine(this));
lines_.back().line() = list;
}
}
void OpenCSV::operator=(List& list)
{
if (list.size() > 0)
{
lines_.resize(lines_.size() + 1, CSVLine(this));
lines_.back().line() = list;
}
}
//OpenCSV::OpenCSV(OpenCSV& csv)
//{
// lines_ = csv.lines();
//}
//void OpenCSV::operator=(OpenCSV& csv)
//{
// lines_ = csv.lines();
//}
OpenCSV::CSVLine& OpenCSV::operator[](size_t idx)
{
if (idx >= lines_.size())
{
lines_.resize(idx + 1, CSVLine(this));
}
return lines_[idx];
}
void OpenCSV::operator>>(std::string& output)
{
std::string str;
for (auto& line : lines_)
{
if (line.empty()) continue;
for (size_t j = 0; j < line.size(); ++j)
{
str.append(j > 0 ? "," + line[j] : line[j]);
}
str.append("\n");
}
if (!CheckFilePath(output))
{
output.append(str);
return;
}
WriteFile(output, str, "wb");
}
void OpenCSV::operator<<(const std::string& input)
{
std::string buffer;
if (CheckFilePath(input))
{
ReadFile(input, buffer, "rb");
}
else
{
buffer = input;
}
lines_.clear();
if (buffer.empty()) return;
size_t row = 0;
size_t column = 0;
for (size_t i = 0; i < buffer.size(); ++i)
{
if (buffer[i] == '\n')
{
if (!lines_.back().empty())
{
++row;
}
column = 0;
continue;
}
if (buffer[i] == ',')
{
++column;
continue;
}
(*this)[row][column].push_back(buffer[i]);
}
}
static bool CheckFilePath(const std::string& filePath)
{
if (!filePath.empty() && filePath.size() < 1024)
{
if (!strstr(filePath.c_str(), "\n") && !strstr(filePath.c_str(), ","))
{
if (strstr(filePath.c_str(), "/")) return true;
}
}
return false;
}
static int64_t ReadFile(const std::string& filePath, std::string& buffer, const char* m)
{
FILE* f = fopen(filePath.c_str(), m);
if (!f) return -1;
fseek(f, 0, SEEK_END);
long len = ftell(f);
fseek(f, 0, SEEK_SET);
buffer.resize(len, 0);
size_t ret = fread((void*)buffer.data(), 1, len, f);
fclose(f);
return ret == 0 ? -1 : len;
}
static int64_t WriteFile(const std::string& filePath, std::string& buffer, const char* m)
{
FILE* f = fopen(filePath.c_str(), m);
if (!f) return -1;
size_t ret = fwrite((void*)buffer.data(), 1, buffer.size(), f);
fclose(f);
return ret == 0 ? -1 : buffer.size();
}