Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C++ csv库调研 #67

Open
dduo518 opened this issue Mar 16, 2023 · 0 comments
Open

C++ csv库调研 #67

dduo518 opened this issue Mar 16, 2023 · 0 comments

Comments

@dduo518
Copy link
Owner

dduo518 commented Mar 16, 2023

CSV(Comma Separated Values)是一种常见的文件格式,它以逗号作为分隔符来存储数据。在处理CSV文件时,使用一个好的CSV库可以使数据处理变得更加容易和高效。在本篇调研中,我们将对一些流行的C++ CSV库进行简要介绍和比较。

1、Fast C++ CSV Parser

Fast C++ CSV Parser是一个高效的CSV解析器,它只包含一个头文件,并且非常容易使用。它使用了 STL 中的 vector 和 string 容器来存储数据,使用了 RAII 的思想来自动管理内存,解析速度非常快。它具有以下特点:

  • 仅依赖C++11标准库

  • 支持UTF-8编码

  • 支持自定义分隔符,自定义行终止符和自动类型推断

  • 支持跳过或解析空行

  • 支持通过迭代器逐行读取数据

  • 具有灵活的接口,可方便地配置解析器

    该库的 Github 仓库地址为:https://github.com/ben-strasser/fast-cpp-csv-parser

该库的使用非常简单,只需包含头文件,然后使用解析器解析CSV文件即可。以下是一个简单的例子:

#include "csv.h"
#include <iostream>
using namespace std;

string file_path = "temp/group.csv";

/**
 * csvReader 读取
 */
void csvReader()
{
  cout << "==== csvReader ==== start" << endl;
  io::CSVReader<2> in(file_path);
  in.read_header(io::ignore_extra_column, "login", "group");
  std::string login;
  std::string group;
  double salary;
  while (in.read_row(login, group))
  {
    // 处理读取到的数据
    cout << "login:" << login << " group:" << group << endl;
  }
  cout << "==== csvReader ==== end" << endl;
  return;
}

/**
 * LineReader 按行读取
 *
 */
void lineReader()
{
  cout << "==== lineReader ==== start" << endl;
  io::LineReader csvLineReader(file_path);
  while (char *ret = csvLineReader.next_line())
  {
    cout << ret << endl;
  }
  cout << "==== lineReader ==== end" << endl;
  return;
}

int main()
{
  lineReader();
  csvReader();
  return 0;
}
==== lineReader ==== start
login,group
8815621,elvin
8815620,elvin
8815622,elvin
==== lineReader ==== end
==== csvReader ==== start
login:8815621 group:elvin
login:8815620 group:elvin
login:8815622 group:elvin
==== csvReader ==== end

缺点: fast-cpp-parser 只提供读csv的功能,不提供写入的功能

RapidCSV

Rapidcsv 是一个易于使用的 C++ CSV 解析器库。它支持 C++11(及更高版本),仅包含头文件并附带一个基本测试套件。

该库的 Github 仓库地址为:https://github.com/d99kris/rapidcsv

它具有以下特点:

  • 可以单独读取数据头header,且支持按列读取,支持读取无头数据

  • 支持行与列定点读取,实现多种读取方式接口

  • 支持将数据读取到容器中,支持多种数据类型,支持自定义转换数据钩子

  • 不需要依赖任何其他第三方库,能够方便地集成到项目中

  • 能够处理各种不同格式的 csv 文件,包括带有头部的和不带有头部的 csv 文件,同时也支持不同的分隔符和换行符

  • 支持跳过空行或者注释

    #include <iostream>
    #include <vector>
    #include "rapidcsv.h"
    #include <string>
    using namespace std;
    
    void readerCsv()
    {
      cout << "======read start=====" << endl;
      rapidcsv::Document doc("temp/group.csv");
      // 读取文件头
      std::vector<string> headers = doc.GetColumnNames();
      for (vector<string>::iterator header = headers.begin(); header != headers.end(); header++)
      {
        cout << "header:" << *header << endl;
      }
    
      // 按列读取
      std::vector<string> columnLogins = doc.GetColumn<string>("login");
      std::vector<string> columnGroups = doc.GetColumn<string>("group");
      for (vector<string>::iterator login = columnLogins.begin(); login != columnLogins.end(); login++)
      {
        cout << "read login:" << *login << endl;
      }
      for (vector<string>::iterator group = columnGroups.begin(); group != columnGroups.end(); group++)
      {
        cout << "read login:" << *group << endl;
      }
      cout << "======read end=====" << endl;
    }
    
    void readerSetDataType()
    {
      rapidcsv::Document doc("temp/test.csv", rapidcsv::LabelParams(0, 0));
    
      std::cout << doc.GetCell<std::string>("Volume", "2017-02-22") << std::endl;
      std::cout << doc.GetCell<int>("Volume", "2017-02-22") << std::endl;
      std::cout << doc.GetCell<long>("Volume", "2017-02-22") << std::endl;
      std::cout << doc.GetCell<long long>("Volume", "2017-02-22") << std::endl;
      std::cout << doc.GetCell<unsigned>("Volume", "2017-02-22") << std::endl;
      std::cout << doc.GetCell<unsigned long>("Volume", "2017-02-22") << std::endl;
      std::cout << doc.GetCell<unsigned long long>("Volume", "2017-02-22") << std::endl;
      std::cout << doc.GetCell<float>("Volume", "2017-02-22") << std::endl;
      std::cout << doc.GetCell<double>("Volume", "2017-02-22") << std::endl;
      std::cout << doc.GetCell<long double>("Volume", "2017-02-22") << std::endl;
      std::cout << doc.GetCell<char>("Volume", "2017-02-22") << std::endl;
    }
    
    void skipEmpty()
    {
      rapidcsv::Document doc("temp/01.csv",
                             rapidcsv::LabelParams(),
                             rapidcsv::SeparatorParams(),
                             rapidcsv::ConverterParams(),
                             rapidcsv::LineReaderParams(false /* pSkipCommentLines */,
                                                        '#' /* pCommentPrefix */,
                                                        true /* pSkipEmptyLines */));
    
      std::vector<string> columnHights = doc.GetColumn<string>("High");
      for (vector<string>::iterator h = columnHights.begin(); h != columnHights.end(); h++)
      {
        cout << "read login:" << *h << endl;
      }
    }
    
    void writeCsv()
    {
      rapidcsv::Document doc;
      doc.SetCell<std::string>(0, -1, "a");
      doc.SetCell<std::string>(1, -1, "b");
      doc.SetCell<std::string>(2, -1, "c");
      doc.SetCell<int>(0, 0, 3);
      doc.SetCell<int>(1, 0, 9);
      doc.SetCell<int>(2, 0, 81);
      doc.SetCell<std::string>(0, 2, "4");
      doc.SetCell<std::string>(1, 2, "16");
      doc.SetCell<std::string>(2, 2, "256");
      doc.SetCell<double>(0, 3, 3.2);
      doc.SetCell<double>(1, 3, 9.3);
      doc.SetCell<double>(2, 3, 81.4);
      doc.Save("temp/02.csv");
    }
    
    
    int main()
    {
      writeCsv();
      skipEmpty();
      system("pause");
      return 0;
    }
    

csv-parse

C++中的csv-parser库旨在提供一种简单直观的语法来解析CSV文件,重点关注处理大型数据集时的性能和内存需求。它使用重叠线程、内存映射IO和高效的数据结构,以最小的内存占用解析文件。它还具有自动推测分隔符、处理注释以及处理不同长度行的能力。该库对编码无限制,可以处理ANSI和UTF-8编码的文件。它还拥有广泛的测试套件

它具有以下特点:

  • 流式读取,读取大文件不需要所有数据都读入内存,节省内存

  • 支持根据列名读取数据、数据类型转换、自定义分隔符、文件头行数,跳过空格,处理不定列数,自定义列名。

  • 支持数据转成json字符串,

  • 支持写入文件,且支持流式写入

  • 支持decimal数据类型

    该库的 Github 仓库地址为:https://github.com/vincentlaucsb/csv-parser

#include "csv.h"
#include <iostream>
using namespace std;

string file_path = "temp/01.csv";

void streamRead()
{
  csv::CSVReader reader(file_path);
  std::vector<std::string> headers = reader.get_col_names();
  // get file header
  for (std::string &header : headers)
  {
    cout << "header:" << header << endl;
  }
  // read data line
  for (csv::CSVRow &row : reader)
  {
    for (csv::CSVField &field : row)
    {
      std::cout << "read:" << field.get<std::string>() << endl;
    }
  }
  // indexing by column Names
  cout << "========" << endl;
  csv::CSVReader reader1(file_path);
  std::vector<std::string> headers1 = reader1.get_col_names();
  for (csv::CSVRow &row : reader1)
  {
    for (vector<string>::iterator header = headers1.begin(); header != headers1.end(); header++)
    {
      std::cout << "read: " << *header << "=" << row[*header].get<string>() << endl;
    }
  }
}

void converJSON()
{
  csv::CSVReader reader(file_path);
  std::stringstream my_json;
  std::vector<std::string> headers = reader.get_col_names();

  for (auto &row : reader)
  {
    my_json << row.to_json(headers) << std::endl;
  }
  std::cout << my_json.str() << std::endl;
}

int main()
{
  converJSON();
  return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant