-
-
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; | |
} |
@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!
Do you have something similar for reading .csv files?