0

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:

inventory.txt

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;
}
Vatine
  • 20,782
  • 4
  • 54
  • 70
ATSpiro
  • 11
  • Your file need to be located under the working directory where is executing your program. Or, you may provide an absolute path (example: `C:\Users\ATSpiro\Desktop\inventory.txt` or `\home\etc\inventory.txt`) – Eduardo Pascual Aseff Oct 01 '21 at 14:36
  • I saved the file where it should be and I also tried inputting the direct path but it still displays that the file was unable to open. – ATSpiro Oct 01 '21 at 14:48
  • why do you use : `filename = filename.substr(0, filename.length() - 1);` Does "filename " contains the extension ? – Jaziri Rami Oct 01 '21 at 15:15
  • @JaziriRami most likely because the OP thinks there is a trailing `\r` being left behind by `getline()`. That is a possibility for `getline(fin)`, if the file is using CRLF-style line breaks, but this code is running on a non-Windows platform. But that is certainly not the case for `getline(cin)`, so that `substr()` should be removed. – Remy Lebeau Oct 01 '21 at 18:02

1 Answers1

1

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:

  • while (!fin.eof()) is bad.

  • 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;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770