OGS
FileIO::CsvInterface Class Reference

Detailed Description

Interface for reading CSV file formats.

Definition at line 40 of file CsvInterface.h.

#include <CsvInterface.h>

Inheritance diagram for FileIO::CsvInterface:
[legend]
Collaboration diagram for FileIO::CsvInterface:
[legend]

Public Member Functions

 CsvInterface ()
 Constructor (only needed for writing files) More...
 
std::size_t getNArrays () const
 Returns the number of vectors currently staged for writing. More...
 
void addIndexVectorForWriting (std::size_t s)
 Adds an index vector of size s to the CSV file. More...
 
void setCsvHeader (bool write_header)
 Stores if the CSV file to be written should include a header or not. More...
 
template<typename T >
bool addVectorForWriting (std::string const &vec_name, std::vector< T > const &vec)
 
bool write () override
 Writes the CSV file. More...
 
- Public Member Functions inherited from BaseLib::IO::Writer
 Writer ()
 
virtual ~Writer ()=default
 
std::string writeToString ()
 Writes the object to a string. More...
 

Static Public Member Functions

static std::vector< std::string > getColumnNames (std::string const &fname, char delim)
 
static int readPoints (std::string const &fname, char delim, std::vector< GeoLib::Point * > &points)
 
static int readPoints (std::string const &fname, char delim, std::vector< GeoLib::Point * > &points, std::string const &x_column_name, std::string const &y_column_name, std::string const &z_column_name="")
 
static int readPoints (std::string const &fname, char delim, std::vector< GeoLib::Point * > &points, std::size_t x_column_idx, std::size_t y_column_idx, std::size_t z_column_idx=std::numeric_limits< std::size_t >::max())
 
template<typename T >
static std::pair< int, std::vector< T > > readColumn (std::string const &fname, char delim, std::string const &column_name)
 
template<typename T >
static std::pair< int, std::vector< T > > readColumn (std::string const &fname, char delim, std::size_t column_idx)
 

Private Member Functions

std::size_t getVectorSize (std::size_t idx) const
 Returns the size of the vector with the given index. More...
 
void writeValue (std::size_t vec_idx, std::size_t in_vec_idx)
 

Static Private Member Functions

static int readPoints (std::ifstream &in, char delim, std::vector< GeoLib::Point * > &points, std::array< std::size_t, 3 > const &column_idx)
 Actual point reader for public methods. More...
 
template<typename T >
static std::pair< int, std::vector< T > > readColumn (std::ifstream &in, char delim, std::size_t column_idx)
 Actual column reader for public methods. More...
 
static std::size_t findColumn (std::string const &line, char delim, std::string const &column_name)
 

Private Attributes

bool _writeCsvHeader {true}
 
std::vector< std::string > _vec_names
 
std::vector< std::any > _data
 

Additional Inherited Members

virtual bool write ()=0
 Writes the object to the internal stream. This method must be implemented by a subclass. The implementation should return true on success, else false. More...
 
- Protected Attributes inherited from BaseLib::IO::Writer
std::ostringstream out
 The stream to write to. More...
 

Constructor & Destructor Documentation

◆ CsvInterface()

FileIO::CsvInterface::CsvInterface ( )
default

Constructor (only needed for writing files)

Member Function Documentation

◆ addIndexVectorForWriting()

void FileIO::CsvInterface::addIndexVectorForWriting ( std::size_t  s)

Adds an index vector of size s to the CSV file.

Definition at line 255 of file CsvInterface.cpp.

256{
257 std::vector<int> idx_vec(s);
258 std::iota(idx_vec.begin(), idx_vec.end(), 0);
259 addVectorForWriting("Index", idx_vec);
260}
bool addVectorForWriting(std::string const &vec_name, std::vector< T > const &vec)
Definition: CsvInterface.h:64
static const double s

References addVectorForWriting(), and MathLib::s.

Referenced by FileIO::SwmmInterface::writeCsvForObject(), and FileIO::SwmmInterface::writeCsvForTimestep().

◆ addVectorForWriting()

template<typename T >
bool FileIO::CsvInterface::addVectorForWriting ( std::string const &  vec_name,
std::vector< T > const &  vec 
)
inline

Adds a data vector to the CSV file. All data vectors have to have the same size. Vectors will be written in the same sequence they have been added to the interface.

Definition at line 64 of file CsvInterface.h.

66 {
67 static_assert(
68 std::is_same_v<T, std::string> || std::is_same_v<T, double> ||
69 std::is_same_v<T, int>,
70 "CsvInterface can only write vectors of strings, doubles or ints.");
71
72 if (!_data.empty())
73 {
74 std::size_t const vec_size(getVectorSize(0));
75 if (vec_size != vec.size())
76 {
77 ERR("Vector size does not match existing data (should be "
78 "{:d}).",
79 vec_size);
80 return false;
81 }
82 }
83
84 _vec_names.push_back(vec_name);
85 _data.push_back(vec);
86 return true;
87 }
void ERR(char const *fmt, Args const &... args)
Definition: Logging.h:44
std::vector< std::any > _data
Definition: CsvInterface.h:255
std::vector< std::string > _vec_names
Definition: CsvInterface.h:254
std::size_t getVectorSize(std::size_t idx) const
Returns the size of the vector with the given index.

References _data, _vec_names, ERR(), and getVectorSize().

Referenced by addIndexVectorForWriting(), FileIO::SwmmInterface::writeCsvForObject(), and FileIO::SwmmInterface::writeCsvForTimestep().

◆ findColumn()

std::size_t FileIO::CsvInterface::findColumn ( std::string const &  line,
char  delim,
std::string const &  column_name 
)
staticprivate

Returns the number of the column with column_name (or std::numeric_limits::max() if no such column has been found).

Definition at line 227 of file CsvInterface.cpp.

229{
230 std::list<std::string> const fields = BaseLib::splitString(line, delim);
231 if (fields.empty())
232 {
233 return std::numeric_limits<std::size_t>::max();
234 }
235
236 std::size_t count(0);
237 for (const auto& field : fields)
238 {
239 if (field == column_name)
240 {
241 break;
242 }
243
244 count++;
245 }
246
247 if (count == fields.size())
248 {
249 return std::numeric_limits<std::size_t>::max();
250 }
251
252 return count;
253}
std::vector< std::string > splitString(std::string const &str)
Definition: StringTools.cpp:28

References BaseLib::splitString().

Referenced by readColumn(), and readPoints().

◆ getColumnNames()

std::vector< std::string > FileIO::CsvInterface::getColumnNames ( std::string const &  fname,
char  delim 
)
static

Returns a vector containing the names of columns in the file (assuming the file has a header)

Definition at line 26 of file CsvInterface.cpp.

28{
29 std::ifstream in(fname.c_str());
30
31 if (!in.is_open())
32 {
33 ERR("CsvInterface::getColumnNames(): Could not open file {:s}.", fname);
34 return std::vector<std::string>();
35 }
36 std::string line;
37 if (!std::getline(in, line))
38 {
39 ERR("CsvInterface::getColumnNames(): Could not read line from file "
40 "{:s}. Is it empty?",
41 fname);
42 return {};
43 }
44
45 if (delim == '\n')
46 {
47 return {};
48 }
49
50 std::list<std::string> fields = BaseLib::splitString(line, delim);
51 if (fields.size() < 2)
52 {
53 for (char const d : {'\t', ';', ','})
54 {
55 fields = BaseLib::splitString(line, d);
56 if (fields.size() > 1)
57 {
58 break;
59 }
60 }
61 }
62 return {begin(fields), end(fields)};
63}

References ERR(), and BaseLib::splitString().

◆ getNArrays()

std::size_t FileIO::CsvInterface::getNArrays ( ) const
inline

Returns the number of vectors currently staged for writing.

Definition at line 47 of file CsvInterface.h.

47{ return _vec_names.size(); }

References _vec_names.

Referenced by FileIO::SwmmInterface::writeCsvForObject(), and FileIO::SwmmInterface::writeCsvForTimestep().

◆ getVectorSize()

std::size_t FileIO::CsvInterface::getVectorSize ( std::size_t  idx) const
private

Returns the size of the vector with the given index.

Definition at line 296 of file CsvInterface.cpp.

297{
298 if (_data[idx].type() == typeid(std::vector<std::string>))
299 {
300 return std::any_cast<std::vector<std::string>>(_data[idx]).size();
301 }
302 if (_data[idx].type() == typeid(std::vector<double>))
303 {
304 return std::any_cast<std::vector<double>>(_data[idx]).size();
305 }
306 if (_data[idx].type() == typeid(std::vector<int>))
307 {
308 return std::any_cast<std::vector<int>>(_data[idx]).size();
309 }
310 return 0;
311}

References _data.

Referenced by addVectorForWriting(), and write().

◆ readColumn() [1/3]

template<typename T >
static std::pair< int, std::vector< T > > FileIO::CsvInterface::readColumn ( std::ifstream &  in,
char  delim,
std::size_t  column_idx 
)
inlinestaticprivate

Actual column reader for public methods.

Definition at line 199 of file CsvInterface.h.

202 {
203 std::vector<T> data_array;
204 std::string line;
205 std::size_t line_count(0);
206 std::size_t error_count(0);
207 while (std::getline(in, line))
208 {
209 line_count++;
210 std::list<std::string> const fields =
211 BaseLib::splitString(line, delim);
212
213 if (fields.size() < column_idx + 1)
214 {
215 ERR("Line {:d} contains not enough columns of data. Skipping "
216 "line...",
217 line_count);
218 error_count++;
219 continue;
220 }
221 auto it = fields.begin();
222 std::advance(it, column_idx);
223
224 std::istringstream stream(*it);
225 T value;
226 if (!(stream >> value))
227 {
228 ERR("Error reading value in line {:d}.", line_count);
229 error_count++;
230 continue;
231 }
232
233 data_array.push_back(value);
234 }
235 return {error_count, data_array};
236 }

References ERR(), and BaseLib::splitString().

◆ readColumn() [2/3]

template<typename T >
static std::pair< int, std::vector< T > > FileIO::CsvInterface::readColumn ( std::string const &  fname,
char  delim,
std::size_t  column_idx 
)
inlinestatic

Definition at line 178 of file CsvInterface.h.

181 {
182 std::ifstream in(fname.c_str());
183 if (!in.is_open())
184 {
185 ERR("CsvInterface::readColumn(): Could not open file {:s}.", fname);
186 return {-1, {}};
187 }
188 return readColumn<T>(in, delim, column_idx);
189 }

References ERR().

◆ readColumn() [3/3]

template<typename T >
static std::pair< int, std::vector< T > > FileIO::CsvInterface::readColumn ( std::string const &  fname,
char  delim,
std::string const &  column_name 
)
inlinestatic

Reads a column of the given name from a CSV file.

Parameters
fnameName of the file to be read
delimDeliminator, default is ','
column_nameThe column's name to read
Returns
An error code (0 = ok, 0<i<max = number of skipped lines, -1 error reading file) and an possibly empty vector containing the read values

Definition at line 155 of file CsvInterface.h.

157 {
158 std::ifstream in(fname.c_str());
159 if (!in.is_open())
160 {
161 ERR("CsvInterface::readColumn(): Could not open file {:s}.", fname);
162 return {-1, {}};
163 }
164
165 std::string line;
166 std::getline(in, line);
167 std::size_t const column_idx =
168 CsvInterface::findColumn(line, delim, column_name);
169 if (column_idx == std::numeric_limits<std::size_t>::max())
170 {
171 ERR("Column '{:s}' not found in file header.", column_name);
172 return {-1, {}};
173 }
174 return readColumn<T>(in, delim, column_idx);
175 }
static std::size_t findColumn(std::string const &line, char delim, std::string const &column_name)

References ERR(), and findColumn().

◆ readPoints() [1/4]

int FileIO::CsvInterface::readPoints ( std::ifstream &  in,
char  delim,
std::vector< GeoLib::Point * > &  points,
std::array< std::size_t, 3 > const &  column_idx 
)
staticprivate

Actual point reader for public methods.

Definition at line 173 of file CsvInterface.cpp.

176{
177 std::array<std::size_t, 3> order = {{0, 1, 2}};
178 std::sort(order.begin(), order.end(),
179 [&column_idx](std::size_t idx1, std::size_t idx2)
180 { return column_idx[idx1] < column_idx[idx2]; });
181 std::array<std::size_t, 3> const column_advance = {
182 {column_idx[order[0]], column_idx[order[1]] - column_idx[order[0]],
183 column_idx[order[2]] - column_idx[order[1]]}};
184
185 std::string line;
186 std::size_t line_count(0);
187 std::size_t error_count(0);
188 std::list<std::string>::const_iterator it;
189
190 while (std::getline(in, line))
191 {
192 line_count++;
193 std::list<std::string> const fields = BaseLib::splitString(line, delim);
194
195 if (fields.size() < column_idx[order[2]] + 1)
196 {
197 ERR("Line {:d} contains not enough columns of data. Skipping "
198 "line...",
199 line_count);
200 error_count++;
201 continue;
202 }
203
204 std::array<double, 3> point{};
205 it = fields.begin();
206 try
207 {
208 std::advance(it, column_advance[0]);
209 point[order[0]] = std::stod(*it);
210 std::advance(it, column_advance[1]);
211 point[order[1]] = std::stod(*it);
212 std::advance(it, column_advance[2]);
213 point[order[2]] =
214 (column_idx[1] == column_idx[2]) ? 0 : std::stod(*it);
215 points.push_back(new GeoLib::Point(point[0], point[1], point[2]));
216 }
217 catch (const std::invalid_argument&)
218 {
219 ERR("Error converting data to coordinates in line {:d}.",
220 line_count);
221 error_count++;
222 }
223 }
224 return error_count;
225}

References ERR(), and BaseLib::splitString().

◆ readPoints() [2/4]

int FileIO::CsvInterface::readPoints ( std::string const &  fname,
char  delim,
std::vector< GeoLib::Point * > &  points 
)
static

Reads 3D points from a CSV file. It is assumed that the file has a header specifying a name for each of the columns. The first three columns will be interpreted as x-, y- and z-coordinate, respectively.

Parameters
fnameName of the file to be read
delimDeliminator, default is ','
pointsA vector containing the 3D points read from the file
Returns
An error code (0 = ok, 0<i<max = number of skipped lines, -1 error reading file)

Definition at line 65 of file CsvInterface.cpp.

67{
68 std::ifstream in(fname.c_str());
69
70 if (!in.is_open())
71 {
72 ERR("CsvInterface::readPoints(): Could not open file {:s}.", fname);
73 return -1;
74 }
75
76 std::string line;
77 std::getline(in, line);
78
79 std::size_t line_count(0);
80 std::size_t error_count(0);
81 std::list<std::string>::const_iterator it;
82 while (std::getline(in, line))
83 {
84 line_count++;
85 std::list<std::string> const fields = BaseLib::splitString(line, delim);
86
87 if (fields.size() < 3)
88 {
89 ERR("Line {:d} contains not enough columns of data. Skipping "
90 "line...",
91 line_count);
92 error_count++;
93 continue;
94 }
95 it = fields.begin();
96 std::array<double, 3> point{};
97 try
98 {
99 point[0] = std::stod(*it);
100 point[1] = std::stod(*(++it));
101 point[2] = std::stod(*(++it));
102 points.push_back(new GeoLib::Point(point[0], point[1], point[2]));
103 }
104 catch (const std::invalid_argument&)
105 {
106 ERR("Error converting data to coordinates in line {:d}.",
107 line_count);
108 }
109 }
110 return error_count;
111}

References ERR(), and BaseLib::splitString().

Referenced by readPoints().

◆ readPoints() [3/4]

int FileIO::CsvInterface::readPoints ( std::string const &  fname,
char  delim,
std::vector< GeoLib::Point * > &  points,
std::size_t  x_column_idx,
std::size_t  y_column_idx,
std::size_t  z_column_idx = std::numeric_limits<std::size_t>::max() 
)
static

Reads 3D points from a headerless CSV file, so columns for x-, y- and z-coordinates have to be specified using indices (starting with 0). If z_column_idx is not given (or set to numeric_limits::max()), all z-coordinates will be set to zero.

Parameters
fnameName of the file to be read
delimDeliminator, default is ','
pointsA vector containing the 3D points read from the file
x_column_idxIndex of the column to be interpreted as x-coordinate
y_column_idxIndex of the column to be interpreted as y-coordinate
z_column_idxIndex of the column to be interpreted as z-coordinate
Returns
An error code (0 = ok, 0<i<max = number of skipped lines, -1 error reading file)

Definition at line 150 of file CsvInterface.cpp.

154{
155 std::ifstream in(fname.c_str());
156
157 if (!in.is_open())
158 {
159 ERR("CsvInterface::readPoints(): Could not open file {:s}.", fname);
160 return -1;
161 }
162
163 if (z_column_idx == std::numeric_limits<std::size_t>::max())
164 {
165 z_column_idx = y_column_idx;
166 }
167 std::array<std::size_t, 3> const column_idx = {
168 {x_column_idx, y_column_idx, z_column_idx}};
169
170 return readPoints(in, delim, points, column_idx);
171}
static int readPoints(std::string const &fname, char delim, std::vector< GeoLib::Point * > &points)

References ERR(), and readPoints().

◆ readPoints() [4/4]

int FileIO::CsvInterface::readPoints ( std::string const &  fname,
char  delim,
std::vector< GeoLib::Point * > &  points,
std::string const &  x_column_name,
std::string const &  y_column_name,
std::string const &  z_column_name = "" 
)
static

Reads 3D points from a CSV file. It is assumed that the file has a header specifying a name for each of the columns. The columns specified in the function call will be used for reading x-, y- and z-coordinates, respectively If z_column_name is an empty string or not given at all, all z-coordinates will be set to zero.

Parameters
fnameName of the file to be read
delimDeliminator, default is ','
pointsA vector containing the 3D points read from the file
x_column_nameName of the column to be interpreted as x-coordinate
y_column_nameName of the column to be interpreted as y-coordinate
z_column_nameName of the column to be interpreted as z-coordinate
Returns
An error code (0 = ok, 0<i<max = number of skipped lines, -1 error reading file)

Definition at line 113 of file CsvInterface.cpp.

118{
119 std::ifstream in(fname.c_str());
120 std::array<std::string, 3> const column_names = {
121 {x_column_name, y_column_name, z_column_name}};
122
123 if (!in.is_open())
124 {
125 ERR("CsvInterface::readPoints(): Could not open file {:s}.", fname);
126 return -1;
127 }
128
129 std::string line;
130 std::getline(in, line);
131 std::array<std::size_t, 3> const column_idx = {
132 {CsvInterface::findColumn(line, delim, x_column_name),
133 CsvInterface::findColumn(line, delim, y_column_name),
134 (z_column_name.empty())
135 ? CsvInterface::findColumn(line, delim, y_column_name)
136 : CsvInterface::findColumn(line, delim, z_column_name)}};
137
138 for (std::size_t i = 0; i < 3; ++i)
139 {
140 if (column_idx[i] == std::numeric_limits<std::size_t>::max())
141 {
142 ERR("Column '{:s}' not found in file header.", column_names[i]);
143 return -1;
144 }
145 }
146
147 return readPoints(in, delim, points, column_idx);
148}

References ERR(), findColumn(), and readPoints().

◆ setCsvHeader()

void FileIO::CsvInterface::setCsvHeader ( bool  write_header)
inline

Stores if the CSV file to be written should include a header or not.

Definition at line 58 of file CsvInterface.h.

58{ _writeCsvHeader = write_header; }

References _writeCsvHeader.

◆ write()

bool FileIO::CsvInterface::write ( )
overridevirtual

Writes the CSV file.

Implements BaseLib::IO::Writer.

Definition at line 262 of file CsvInterface.cpp.

263{
264 if (_data.empty())
265 {
266 ERR("CsvInterface::write() - No data to write.");
267 return false;
268 }
269
270 std::size_t const n_vecs(_data.size());
271 std::size_t const vec_size(getVectorSize(0));
272
273 if (_writeCsvHeader)
274 {
275 out << _vec_names[0];
276 for (std::size_t i = 1; i < n_vecs; ++i)
277 {
278 out << "\t" << _vec_names[i];
279 }
280 out << "\n";
281 }
282
283 for (std::size_t j = 0; j < vec_size; ++j)
284 {
285 writeValue(0, j);
286 for (std::size_t i = 1; i < n_vecs; ++i)
287 {
288 out << "\t";
289 writeValue(i, j);
290 }
291 out << "\n";
292 }
293 return true;
294}
std::ostringstream out
The stream to write to.
Definition: Writer.h:46
void writeValue(std::size_t vec_idx, std::size_t in_vec_idx)

References _data, _vec_names, _writeCsvHeader, ERR(), getVectorSize(), BaseLib::IO::Writer::out, and writeValue().

◆ writeValue()

void FileIO::CsvInterface::writeValue ( std::size_t  vec_idx,
std::size_t  in_vec_idx 
)
private

Writes a value from a vector to the file.

Parameters
vec_idxIndex of the vector
in_vec_idxEntry in the selected vector

Definition at line 313 of file CsvInterface.cpp.

314{
315 if (_data[vec_idx].type() == typeid(std::vector<std::string>))
316 {
317 out << std::any_cast<std::vector<std::string>>(
318 _data[vec_idx])[in_vec_idx];
319 }
320 else if (_data[vec_idx].type() == typeid(std::vector<double>))
321 {
322 out << std::any_cast<std::vector<double>>(_data[vec_idx])[in_vec_idx];
323 }
324 else if (_data[vec_idx].type() == typeid(std::vector<int>))
325 {
326 out << std::any_cast<std::vector<int>>(_data[vec_idx])[in_vec_idx];
327 }
328}

References _data.

Referenced by write().

Member Data Documentation

◆ _data

std::vector<std::any> FileIO::CsvInterface::_data
private

Definition at line 255 of file CsvInterface.h.

Referenced by addVectorForWriting(), getVectorSize(), write(), and writeValue().

◆ _vec_names

std::vector<std::string> FileIO::CsvInterface::_vec_names
private

Definition at line 254 of file CsvInterface.h.

Referenced by addVectorForWriting(), getNArrays(), and write().

◆ _writeCsvHeader

bool FileIO::CsvInterface::_writeCsvHeader {true}
private

Definition at line 253 of file CsvInterface.h.

Referenced by setCsvHeader(), and write().


The documentation for this class was generated from the following files: