0

is there any library or example for reading a csv file in C++ like the csv module in Python?

What I need is a function to read a csv file and put each column element of a row in a map with the header name as the key value.

jazz
  • 349
  • 3
  • 13
  • Read the file line by line, then use strtok() function with delimiter as csv delimiter and store the values in a map – Anshul Mar 11 '15 at 09:26
  • I think this is a duplicate question. Have a look at http://stackoverflow.com/questions/1120140/how-can-i-read-and-parse-csv-files-in-c – user3590169 Mar 11 '15 at 09:27

1 Answers1

2

I can answer myself. I wrote a CSVDict class.

#include <iterator>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
#include <map>

class CSVDict {
public:
    CSVDict(std::string fileName, int headerRow) {
        file = std::ifstream(fileName);
        for (int i = 0; i < headerRow; i++){ readNextRow(file); }
        m_header = m_data;
    }
    std::string const& operator[](std::size_t index) const {
        return m_data[index];
    }
    std::string const& operator[](std::string index) const {
        return m_dataMap.find(index)->second;
    }
    bool readNextRowMap() {
        readNextRow(file);
        if (!file) return false;
        m_dataMap.clear();
        auto it_data = m_data.begin();
        for (auto it = m_header.begin(); it != m_header.end(); ++it) {
            m_dataMap[*it] = *it_data;
            ++it_data;
        }
        return true;
    }
private:
    void readNextRow(std::istream& str) {
        std::string         line;
        std::getline(str, line);
        if (!str) return;

        std::stringstream   lineStream(line);
        std::string         cell;

        m_data.clear();
        while (std::getline(lineStream, cell, ';')) {
            m_data.push_back(cell);
        }
    }
    std::vector<std::string>    m_data;
    std::vector<std::string>    m_header;
    std::map<std::string, std::string> m_dataMap;
    std::ifstream file;
};


int main()
{
    CSVDict              dict("1.csv", 2);
    while (dict.readNextRowMap()) {
        std::cout << dict[0] << " " << dict[1] << " " << dict[2] << " " << dict[3] << " " << dict[4] << " " << dict[5] << " " << dict[6] << "\n";
    }

    CSVDict              dict1("1.csv", 2);
    dict1.readNextRowMap();
    std::cout << dict1["ipField"] << " " << dict1["mdBeamEnergy"] << " " << dict1["mdBeamCurrent"] << " " << dict1["mcoBeamSizeId"] << " " << dict1["mdGantryAngle"] << " " << dict1["miLayerNumber"] << "\n";
    dict1.readNextRowMap();
    std::cout << dict1["ipField"] << " " << dict1["mdBeamEnergy"] << " " << dict1["mdBeamCurrent"] << " " << dict1["mcoBeamSizeId"] << " " << dict1["mdGantryAngle"] << " " << dict1["miLayerNumber"] << "\n";
    dict1.readNextRowMap();
    std::cout << dict1["ipField"] << " " << dict1["mdBeamEnergy"] << " " << dict1["mdBeamCurrent"] << " " << dict1["mcoBeamSizeId"] << " " << dict1["mdGantryAngle"] << " " << dict1["miLayerNumber"] << "\n";

    dict.readNextRowMap();
    std::cout << dict[0] << " " << dict[1] << " " << dict[2] << " " << dict[3] << " " << dict[4] << " " << dict[5] << " " << dict[6] << "\n";
    return 0;
}

Example csv file:

#VALUES;;;;;;
ipField;mdBeamEnergy;mdBeamCurrent;mcoBeamSizeId;mdGantryAngle;miLayerNumber;mbRoomSwitchingLayer
24.30815;172.152971;24.30815;4;65;1;1
24.30815;172.152971;24.30815;4;65;2;0
24.30815;172.152971;24.30815;4;65;3;0
24.30815;172.152971;24.30815;4;65;4;0
24.30815;172.152971;24.30815;4;65;5;0
24.30815;172.152971;24.30815;4;65;6;0
24.30815;172.152971;24.30815;4;65;7;0
24.30815;172.152971;24.30815;4;65;8;0

usage (see main function in example):

class constructor needs to have the csv filename and the csv header line number every readNextRowMap gets the values of the next line in the csv file you can address the values either by number index or by header name

downside:

csv file has to have a header line

jazz
  • 349
  • 3
  • 13