Reputation: 13
I want to open a txt file by user input and display it when the code is ran so I can then modify it.
Every time I have tried to open the file it does not open. Do I need to save the file in a certain place or is my code just wrong?
This is what my file looks like if it helps:
My code:
const int max_items = 30;
Item items[max_items];
char mainChoice, subChoice;
int num_items = 0;
int parts;
string filename, description;
ifstream fin;
cout << "Enter the name of the inventory file : ";
getline(cin, filename);
filename = filename.substr(0, filename.length() - 1);
fin.open(filename.c_str());
if (fin.is_open())
{
while (!fin.eof())
{
getline(fin, items[num_items].description);
items[num_items].description = items[num_items].description.substr(0, items[num_items].description.length() - 1);
fin >> items[num_items].num_parts;
fin.ignore(100, '\n');
num_items++;
}
fin.close();
}
else
{
cout << "Unable to open file" << endl;
}
Upvotes: 0
Views: 569
Reputation: 595772
You are unconditionally removing the last character from filename
before using it. std::getline()
does not output the '\n'
character that terminates the line. I'm guessing that you expect an Enter press on the terminal to generate an \r\n
sequence and then std::getline()
to output the '\r'
and dismiss the '\n'
. That is simply not the case when reading from std::cin
, only '\n'
is generated, which std::getline()
does not output. So you need to get rid of that substr()
call altogether and just use filename
as-is:
cout << "Enter the name of the inventory file : ";
getline(cin, filename);
//filename = filename.substr(0, filename.length() - 1);
fin.open(filename.c_str());
...
However, it is certainly possible for std::getline()
to output an '\r'
character when reading from a file, if the file is using CRLF-style line breaks, and the code is not running on Windows. In that case, you do need to account for the extra '\r'
, but it should be done conditionally instead, eg:
getline(fin, description);
if (!description.empty() && description.back() == '\r')
description.pop_back();
items[num_items].description = description;
That being said, there are some other issues with your code:
when calling a stream's ignore()
method to discard everything up to a specified delimiter, don't use a hard-coded length value. Use std::numeric_limits<std::streamsize>::max()
instead.
you are overflowing your items[]
array, if the file has more than 30 items in it. You should use a std::vector
when you don't know the number of items at compile-time.
you are not parsing the contents of the file correctly at all, given the text file you have shown.
Try something more like this instead:
#include <iostream>
#include <fstream>
#include <string>
//#include <vector>
#include <limits>
using namespace std;
const int max_items = 30;
Item items[max_items];
int num_items = 0;
//vector<Item> items;
cout << "Enter the name of the inventory file : ";
string filename;
getline(cin, filename);
ifstream fin(filename.c_str());
if (fin.is_open())
{
// ignore the file header
fin.ignore(numeric_limits<streamsize>::max(), '\n');
fin.ignore(numeric_limits<streamsize>::max(), '\n');
char description[25];
while (fin.get(description, 25))
{
size_t len = fin.gcount();
if (len > 0 && description[len-1] == '\r')
--len;
/*
Item item;
item.description = string(description, len);
fin >> item.num_parts;
items.push_back(item);
*/
items[num_items].description = string(description, len);
fin >> item[num_items].num_parts;
++num_items;
if (num_items == max_items)
break;
//
fin.ignore(numeric_limits<streamsize>::max(), '\n');
}
fin.close();
// use items as needed...
}
else
{
cout << "Unable to open file" << endl;
}
Alternatively, use std::getline()
to read whole lines from the file, so you don't have to call ignore()
on each iteration. You can use std::istringstream
to parse each line, eg:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
//#include <vector>
#include <limits>
using namespace std;
const int max_items = 30;
Item items[max_items];
int num_items = 0;
//vector<Item> items;
cout << "Enter the name of the inventory file : ";
string filename;
getline(cin, filename);
ifstream fin(filename.c_str());
if (fin.is_open())
{
// ignore the file header
fin.ignore(numeric_limits<streamsize>::max(), '\n');
fin.ignore(numeric_limits<streamsize>::max(), '\n');
string line;
while (getline(fin, line))
{
istringstream iss(line);
char description[25];
iss.get(description, 25);
size_t len = iss.gcount();
if (len > 0 && description[len-1] == '\r')
--len;
/*
Item item;
item.description = string(description, len);
iss >> item.num_parts;
items.push_back(item);
*/
items[num_items].description = string(description, len);
iss >> item[num_items].num_parts;
++num_items;
if (num_items == max_items)
break;
}
fin.close();
// use items as needed...
}
else
{
cout << "Unable to open file" << endl;
}
Upvotes: 1