I'm trying to write a function to load a .csv
file into a vector<item>
:
std::vector<Item> LoadDataFromFileStruct(std::string filePath)
{
std::fstream fileCon;
fileCon.open(filePath);
std::vector<Item> items{};
while (fileCon.peek() != EOF) {
Item item{};
while (fileCon.peek() != '\n')
{
std::getline(fileCon, item.marca, ',');
std::getline(fileCon, item.modelo, ',');
std::getline(fileCon, item.cv, ',');
std::getline(fileCon, item.m2h, ',');
std::getline(fileCon, item.preço, '\n');
}
items.push_back(item);
}
fileCon.close();
return items;
}
The problem I'm having is that when the compiler gets to line 6 (std::vector<Item> items{};
), it skips to the return items;
line, I checked this using the Visual Studio debug tool.
The program compiles.
Also, I realize that it will get stuck in the inner while
loop.
I'm very new to programming, so it might be something simple.
I have also written the following code in order to load data from the .csv
file into a vector<vector<string>>
, which works without this problem.
std::vector<std::vector<std::string>> LoadDataFromFile(std::string filePath)
{
//Vars
std::ifstream fileCon;
fileCon.open(filePath);
std::vector<std::vector<std::string>> loadedData;
//Iterator
if (!fileCon.is_open()) {
std::cout << "Unable to open files";
return std::vector<std::vector<std::string>>{};
}
while (fileCon.peek() != EOF) {
std::vector<std::string> row;
std::string celStr{ 0 };
while (fileCon.peek()!='\n')
{
std::getline(fileCon, celStr,',');
row.push_back(celStr);
if (celStr.back()=='\n')
{
break;
}
}
loadedData.push_back(row);
}
fileCon.close();
return loadedData;
}
I don't really know what to try next. I suspect that using a vector
of struct objects was a bad idea.
The problem I'm having is that when the compiler gets to line 6 (
std::vector<Item> items{};
), it skips to thereturn items;
line, I checked this using the Visual Studio debug tool.
The only way I can see that happening is if fileCon.peek()
is returning EOF
immediately, ie if the file was not opened successfully, which you are not checking for in the 1st example (but you are in the 2nd example).
That being said, there is no good reason to use peek()
at all in either example. Both can be made simpler by reading the file line-by-line using std::getline()
and parsing each line with std::istringstream
, eg:
std::vector<Item> LoadDataFromFileStruct(std::string filePath)
{
std::ifstream fileCon(filePath);
std::vector<Item> items;
if (!fileCon.is_open()) {
std::cout << "Unable to open file\n";
return items;
}
std::string line;
while (std:getline(fileCon, line)) {
std::istringstream iss(line);
Item item;
std::getline(iss, item.marca, ',');
std::getline(iss, item.modelo, ',');
std::getline(iss, item.cv, ',');
std::getline(iss, item.m2h, ',');
std::getline(iss, item.preço);
items.push_back(item);
}
return items;
}
std::vector<std::vector<std::string>> LoadDataFromFile(std::string filePath)
{
std::ifstream fileCon(filePath);
std::vector<std::vector<std::string>> loadedData;
if (!fileCon.is_open()) {
std::cout << "Unable to open file\n";
return loadedData;
}
std::string line;
while (std::getline(fileCon, line)) {
std::istringstream iss(line);
std::vector<std::string> row;
std::string celStr;
while (std::getline(iss, celStr, ',')) {
row.push_back(celStr);
}
loadedData.push_back(row);
}
return loadedData;
}
In the 1st example, I would even suggest taking it a step further by defining an operator>>
for Item
, and then you can simply use while (fileCon >> item)
instead, eg:
std::istream& operator>>(std::istream &input, Item &item)
{
std::string line;
if (std:getline(input, line)) {
std::istringstream iss(line);
std::getline(iss, item.marca, ',');
std::getline(iss, item.modelo, ',');
std::getline(iss, item.cv, ',');
std::getline(iss, item.m2h, ',');
std::getline(iss, item.preço);
if (iss.fail()) {
input.setstate(std::ios_base::failbit);
}
}
return input;
}
std::vector<Item> LoadDataFromFileStruct(std::string filePath)
{
std::ifstream fileCon(filePath);
std::vector<Item> items;
if (!fileCon.is_open()) {
std::cout << "Unable to open file\n";
return items;
}
Item item;
while (fileCon >> item) {
items.push_back(item);
}
return items;
}
Or, even construct the returned vector
using a std::istream_iterator
, eg:
std::vector<Item> LoadDataFromFileStruct(std::string filePath)
{
std::ifstream fileCon(filePath);
if (!fileCon.is_open()) {
std::cout << "Unable to open file\n";
return std::vector<Item>{};
}
return std::vector<Item>{
std::istream_iterator<Item>(fileCon),
std::istream_iterator<Item>{}
};
// or simply:
// return {std::istream_iterator<Item>(fileCon), {}};
}