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 int readColumn (std::string const &fname, char delim, std::vector< T > &data_array, std::string const &column_name)
 
template<typename T >
static int readColumn (std::string const &fname, char delim, std::vector< T > &data_array, 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 int readColumn (std::ifstream &in, char delim, std::vector< T > &data_array, 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

- 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 252 of file CsvInterface.cpp.

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

References addVectorForWriting().

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:42
std::vector< std::any > _data
Definition: CsvInterface.h:253
std::vector< std::string > _vec_names
Definition: CsvInterface.h:252
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 224 of file CsvInterface.cpp.

226 {
227  std::list<std::string> const fields = BaseLib::splitString(line, delim);
228  if (fields.empty())
229  {
230  return std::numeric_limits<std::size_t>::max();
231  }
232 
233  std::size_t count(0);
234  for (const auto& field : fields)
235  {
236  if (field == column_name)
237  {
238  break;
239  }
240 
241  count++;
242  }
243 
244  if (count == fields.size())
245  {
246  return std::numeric_limits<std::size_t>::max();
247  }
248 
249  return count;
250 }
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::readPoints(): 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  return {};
40  }
41 
42  std::list<std::string> fields;
43  if (delim != '\n')
44  {
45  fields = BaseLib::splitString(line, delim);
46  }
47 
48  if (fields.size() < 2)
49  {
50  for (char const d : {'\t', ';', ','})
51  {
52  fields = BaseLib::splitString(line, d);
53  if (fields.size() > 1)
54  {
55  break;
56  }
57  }
58  }
59  return {begin(fields), end(fields)};
60 }

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 293 of file CsvInterface.cpp.

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

References _data.

Referenced by addVectorForWriting(), and write().

◆ readColumn() [1/3]

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

Actual column reader for public methods.

Definition at line 199 of file CsvInterface.h.

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

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

◆ readColumn() [2/3]

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

Definition at line 179 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, data_array, column_idx);
189  }

References ERR().

◆ readColumn() [3/3]

template<typename T >
static int FileIO::CsvInterface::readColumn ( std::string const &  fname,
char  delim,
std::vector< T > &  data_array,
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 ','
data_arrayA vector containing the data read from the file
column_nameThe column's name to read
Returns
An error code (0 = ok, 0<i<max = number of skipped lines, -1 error reading file)

Definition at line 155 of file CsvInterface.h.

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

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

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 62 of file CsvInterface.cpp.

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

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 147 of file CsvInterface.cpp.

151 {
152  std::ifstream in(fname.c_str());
153 
154  if (!in.is_open())
155  {
156  ERR("CsvInterface::readPoints(): Could not open file {:s}.", fname);
157  return -1;
158  }
159 
160  if (z_column_idx == std::numeric_limits<std::size_t>::max())
161  {
162  z_column_idx = y_column_idx;
163  }
164  std::array<std::size_t, 3> const column_idx = {
165  {x_column_idx, y_column_idx, z_column_idx}};
166 
167  return readPoints(in, delim, points, column_idx);
168 }
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 110 of file CsvInterface.cpp.

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

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 259 of file CsvInterface.cpp.

260 {
261  if (_data.empty())
262  {
263  ERR("CsvInterface::write() - No data to write.");
264  return false;
265  }
266 
267  std::size_t const n_vecs(_data.size());
268  std::size_t const vec_size(getVectorSize(0));
269 
270  if (_writeCsvHeader)
271  {
272  out << _vec_names[0];
273  for (std::size_t i = 1; i < n_vecs; ++i)
274  {
275  out << "\t" << _vec_names[i];
276  }
277  out << "\n";
278  }
279 
280  for (std::size_t j = 0; j < vec_size; ++j)
281  {
282  writeValue(0, j);
283  for (std::size_t i = 1; i < n_vecs; ++i)
284  {
285  out << "\t";
286  writeValue(i, j);
287  }
288  out << "\n";
289  }
290  return true;
291 }
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 310 of file CsvInterface.cpp.

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

References _data.

Referenced by write().

Member Data Documentation

◆ _data

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

Definition at line 253 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 252 of file CsvInterface.h.

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

◆ _writeCsvHeader

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

Definition at line 251 of file CsvInterface.h.

Referenced by setCsvHeader(), and write().


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