-
-
Save rudolfovich/f250900f1a833e715260a66c87369d15 to your computer and use it in GitHub Desktop.
#pragma once | |
#include <string> | |
#include <iostream> | |
#include <fstream> | |
#include <sstream> | |
class csvfile; | |
inline static csvfile& endrow(csvfile& file); | |
inline static csvfile& flush(csvfile& file); | |
class csvfile | |
{ | |
std::ofstream fs_; | |
bool is_first_; | |
const std::string separator_; | |
const std::string escape_seq_; | |
const std::string special_chars_; | |
public: | |
csvfile(const std::string filename, const std::string separator = ";") | |
: fs_() | |
, is_first_(true) | |
, separator_(separator) | |
, escape_seq_("\"") | |
, special_chars_("\"") | |
{ | |
fs_.exceptions(std::ios::failbit | std::ios::badbit); | |
fs_.open(filename); | |
} | |
~csvfile() | |
{ | |
flush(); | |
fs_.close(); | |
} | |
void flush() | |
{ | |
fs_.flush(); | |
} | |
void endrow() | |
{ | |
fs_ << std::endl; | |
is_first_ = true; | |
} | |
csvfile& operator << ( csvfile& (* val)(csvfile&)) | |
{ | |
return val(*this); | |
} | |
csvfile& operator << (const char * val) | |
{ | |
return write(escape(val)); | |
} | |
csvfile& operator << (const std::string & val) | |
{ | |
return write(escape(val)); | |
} | |
template<typename T> | |
csvfile& operator << (const T& val) | |
{ | |
return write(val); | |
} | |
private: | |
template<typename T> | |
csvfile& write (const T& val) | |
{ | |
if (!is_first_) | |
{ | |
fs_ << separator_; | |
} | |
else | |
{ | |
is_first_ = false; | |
} | |
fs_ << val; | |
return *this; | |
} | |
std::string escape(const std::string & val) | |
{ | |
std::ostringstream result; | |
result << '"'; | |
std::string::size_type to, from = 0u, len = val.length(); | |
while (from < len && | |
std::string::npos != (to = val.find_first_of(special_chars_, from))) | |
{ | |
result << val.substr(from, to - from) << escape_seq_ << val[to]; | |
from = to + 1; | |
} | |
result << val.substr(from) << '"'; | |
return result.str(); | |
} | |
}; | |
inline static csvfile& endrow(csvfile& file) | |
{ | |
file.endrow(); | |
return file; | |
} | |
inline static csvfile& flush(csvfile& file) | |
{ | |
file.flush(); | |
return file; | |
} |
#include "csvfile.h" | |
int main() | |
{ | |
try | |
{ | |
csvfile csv("MyTable.csv"); // throws exceptions! | |
// Hearer | |
csv << "X" << "VALUE" << endrow; | |
// Data | |
int i = 1; | |
csv << i++ << "String value" << endrow; | |
csv << i++ << 123 << endrow; | |
csv << i++ << 1.f << endrow; | |
csv << i++ << 1.2 << endrow; | |
csv << i++ << "One more string" << endrow; | |
csv << i++ << "\"Escaped\"" << endrow; | |
csv << i++ << "=HYPERLINK(\"https://playkey.net\"; \"Playkey Service\")" << endrow; | |
} | |
catch (const std::exception &ex) | |
{ | |
std::cout << "Exception was thrown: " << ex.what() << std::endl; | |
} | |
return 0; | |
} |
Is there a way to append data to already existing file?
@nassausky, thanks, yes, i'll add comments.
@rajesh23sharma, just open file in append mode at line 21
fs_.open(filename, std::ofstream::app);
more info about open mode
How can we prevent the trailing separator at the end of each line ?
Could we handle that in the endrow
function ?
@fabito, I've fixed trailing separator issue.
Also added escape quotes logic.
Would you consider adding a license to that?
is this open source? id love to use this with a program im developing.
id love to use this with a program im developing
@AlexanderMoran1995, yes, you may use, change, distribute this.
Very useful and thanks a lot, good luck!
Do you have something similar for reading .csv files?
@davidglavas, I don't have it.
Reading is a bit more complicated.
So you may face different types of CSV file formats, so you must be ready to parse all of them and guess what CSV file format you are parsing.
Of course you can make simple parser with only one supported format if you work with internal files at your company, but i believe that it will be bad decision.
What about taking an already open stream in the constructor and transforming it into a csv_writer
?
BTW: "Hearer" in main.cpp (8) should be "Header".
@rudolfovich Can you confirm you have licensed this under the BSD 3-clause?
Thank You for the code, Worked great in a project I was working on🎉
@rudolfovich Can you confirm you have licensed this under the BSD 3-clause?
Yes, this source code may be used under BSD 3-clause.
Thank You for the code, Worked great in a project I was working on🎉
Glad to hear it, you are welcome!
Wow that class looks short and sweet. Can you add comments to each line to tell us what it does. I'm especially interested on how each of the overload operators work.