How to Read and Parse CSV Files in C++

Read .csv file in C

Hopefully this would get you started

See it live on http://ideone.com/l23He (using stdin)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char* getfield(char* line, int num)
{
const char* tok;
for (tok = strtok(line, ";");
tok && *tok;
tok = strtok(NULL, ";\n"))
{
if (!--num)
return tok;
}
return NULL;
}

int main()
{
FILE* stream = fopen("input", "r");

char line[1024];
while (fgets(line, 1024, stream))
{
char* tmp = strdup(line);
printf("Field 3 would be %s\n", getfield(tmp, 3));
// NOTE strtok clobbers tmp
free(tmp);
}
}

Output:

Field 3 would be nazwisko
Field 3 would be Kowalski
Field 3 would be Nowak

How can I read and parse CSV files in C++?

If you don't care about escaping comma and newline,

AND you can't embed comma and newline in quotes (If you can't escape then...)

then its only about three lines of code (OK 14 ->But its only 15 to read the whole file).

std::vector<std::string> getNextLineAndSplitIntoTokens(std::istream& str)
{
std::vector<std::string> result;
std::string line;
std::getline(str,line);

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

while(std::getline(lineStream,cell, ','))
{
result.push_back(cell);
}
// This checks for a trailing comma with no data after it.
if (!lineStream && cell.empty())
{
// If there was a trailing comma then add an empty element.
result.push_back("");
}
return result;
}

I would just create a class representing a row.

Then stream into that object:

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

class CSVRow
{
public:
std::string_view operator[](std::size_t index) const
{
return std::string_view(&m_line[m_data[index] + 1], m_data[index + 1] - (m_data[index] + 1));
}
std::size_t size() const
{
return m_data.size() - 1;
}
void readNextRow(std::istream& str)
{
std::getline(str, m_line);

m_data.clear();
m_data.emplace_back(-1);
std::string::size_type pos = 0;
while((pos = m_line.find(',', pos)) != std::string::npos)
{
m_data.emplace_back(pos);
++pos;
}
// This checks for a trailing comma with no data after it.
pos = m_line.size();
m_data.emplace_back(pos);
}
private:
std::string m_line;
std::vector<int> m_data;
};

std::istream& operator>>(std::istream& str, CSVRow& data)
{
data.readNextRow(str);
return str;
}
int main()
{
std::ifstream file("plop.csv");

CSVRow row;
while(file >> row)
{
std::cout << "4th Element(" << row[3] << ")\n";
}
}

But with a little work we could technically create an iterator:

class CSVIterator
{
public:
typedef std::input_iterator_tag iterator_category;
typedef CSVRow value_type;
typedef std::size_t difference_type;
typedef CSVRow* pointer;
typedef CSVRow& reference;

CSVIterator(std::istream& str) :m_str(str.good()?&str:nullptr) { ++(*this); }
CSVIterator() :m_str(nullptr) {}

// Pre Increment
CSVIterator& operator++() {if (m_str) { if (!((*m_str) >> m_row)){m_str = nullptr;}}return *this;}
// Post increment
CSVIterator operator++(int) {CSVIterator tmp(*this);++(*this);return tmp;}
CSVRow const& operator*() const {return m_row;}
CSVRow const* operator->() const {return &m_row;}

bool operator==(CSVIterator const& rhs) {return ((this == &rhs) || ((this->m_str == nullptr) && (rhs.m_str == nullptr)));}
bool operator!=(CSVIterator const& rhs) {return !((*this) == rhs);}
private:
std::istream* m_str;
CSVRow m_row;
};


int main()
{
std::ifstream file("plop.csv");

for(CSVIterator loop(file); loop != CSVIterator(); ++loop)
{
std::cout << "4th Element(" << (*loop)[3] << ")\n";
}
}

Now that we are in 2020 lets add a CSVRange object:

class CSVRange
{
std::istream& stream;
public:
CSVRange(std::istream& str)
: stream(str)
{}
CSVIterator begin() const {return CSVIterator{stream};}
CSVIterator end() const {return CSVIterator{};}
};

int main()
{
std::ifstream file("plop.csv");

for(auto& row: CSVRange(file))
{
std::cout << "4th Element(" << row[3] << ")\n";
}
}

Parse CSV file in C

Take a look at libcsv, which is a CSV library written in ANSI C89.

Reading CSV from text file in C

You just stored pointers into a local buffer. When you leave load() this buffer is gone and not accessible anymore.

You must allocate memory for name and email before you can copy it into the Owner struct.

char *tok;
tok = strtok(NULL, ",");
len = strlen(tok);
owner->name = malloc(len + 1);
strcpy(owner->name, tok);
...

[EDIT: you need to allocate len+1 bytes so you have space for the terminating NUL character. -Zack]

How to parse and arrange lines of a csv file based on matching word in C?

I could write the code to get the required output. Below is the code:

#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<fcntl.h>
#include<string.h>

int main(int argc, char ** argv)
{
struct filedata {
char nation[8];
char content[50];
};

char line[100];
char *inputFile = argv[1];
FILE *input_csv_file;
int iter = 0, c;

char * tok;
int count = 0;
char ch;
char country[] = "country";
char header_line[50];

input_csv_file = fopen(inputFile, "rt");

//count line numbers of the input csv
for(ch = getc(input_csv_file); ch!= EOF; ch=getc(input_csv_file))
if(ch == '\n')
count = count + 1;


fclose(input_csv_file);


count = count -1;

struct filedata * record[count];
input_csv_file = fopen(inputFile, "rt");

if(input_csv_file == 0)
{
printf("Can not open input file\n");
} else
{
while(fgets(line, sizeof line, input_csv_file) != NULL)
{
//printf("-- line = %s\n", line);
int s_line = sizeof line;
char dup_line[s_line];
strcpy(dup_line, line);

int h = 0;
int s_token;

tok = strtok(line, ",");

while(tok != NULL)
{
h++;
if(h == 3)
{
s_token = sizeof tok;
break;
}
tok = strtok(NULL, ",");
}


// skipping the line having column headers
if(compare_col(tok, country) == 0) {
strcpy(header_line, dup_line);
continue;
}

iter++;
c = iter - 1;

record[c] = (struct filedata*)malloc(sizeof(struct filedata));
strcpy(record[c]->nation, tok);
strcpy(record[c]->content, dup_line);
} //while

struct filedata * temp;

FILE * fptr;
fptr = fopen("nation_csv.txt", "w");
if(fptr == NULL)
{
printf("Error in opening the file to write\n");
exit(1);
}

// sorting the arr of struct nation wise
for(iter=1; iter < count; iter++)
for(c =0 ; c < count -1; c++) {
if(strcmp(record[c]->nation, record[c+1]->nation) > 0) {
temp = record[c];
record[c] = record[c+1];
record[c+1] = temp;
}
}

for(iter=0; iter < count; ++iter)
{
if(iter == 0) {
fprintf(fptr, "%s", header_line);
continue;
}

fprintf(fptr, "%s", record[iter]->content);
}
fclose(fptr);
}
fclose(input_csv_file);
}

int compare_col(char a[], char b[] )
{
int c = 0;
while(a[c] == b[c]) {
if(a[c] == '\0' || b[c] == '\0')
break;
c++;

}

if(a[c] == '\0' && b[c] == '\0')
return 0;
else
return -1;
}

Thanks for all your inputs. Any further inputs to make it better are much appreciated.

Thanks



Related Topics



Leave a reply



Submit