0

I have been working on just importing from a file into my objects for 2+ days and read the book, searched the internet and basically tried everything I could think of.. so here is a last ditch (of course I'll never give up haha). >>>I have a class ItemClass for software objects, which I place in a vector eventually to be updated and written back to the file. My perfect outcome would be to read the contents of the file directly into the vector of software objects but right now I just want to get the contents of the file correctly. The file I am reading from is thus:

Adobe Photoshop
CS5
5 21 580
Norton Utilities
n/a
1 10 50
Norton System Works
2009
3 6 50
Visual Studio Professional
2010
4 19 700
Microsoft Office
2010
6 27 150

Here is the code that is not behaving as expected:

int main() {

//declare  new classes to play with file input/output
ItemClass pshop;
ItemClass nU;
ItemClass sW;
ItemClass vsP;

//declare a vector to hold the objects for later sorting and placing into a tree structure
vector<ItemClass> classVector;
ifstream file;
file.open("software.txt");

if (file.fail()) {
    cout << "Error reading from file." << endl;
}
        //edited code
        std::string kqpline;
        getline(file, kqpline);
        std::istringstream kqpstream(kqpline);
        kqpstream >> k >> q >> p;

        pshop.setItem(k, n, v, q, p);


       getline(file, n);
       getline(file, v);
       getline(file, kqpline);
       kqpstream >> k >> q >> p;
       nU.setItem(k, n, v, q, p);
       nU.setItem(k, n, v, q, p); //end edited code- this interface is killing me so I didn't update the rest of my code- but it looked like this

    mark = file.tellg();
    file.seekg(mark);
    getline(file, n);
    getline(file, v);
    file >> k;
    file >> q;
    file >> p;
    sW.setItem(k, n, v, q, p);

    mark = file.tellg();
    file.seekg(mark);
    getline(file, n);
    getline(file, v);
    file >> k;
    file >> q;
    file >> p;
    vsP.setItem(k, n, v, q, p);

file.close();
    cout << "here is the object we extracted from 'file': " << endl;
      pshop.printItem();
      nU.printItem();
      sW.printItem();
      vsP.printItem();

classVector.push_back(pshop);
classVector.push_back(nortonU);
classVector.push_back(vsPro);
classVector.push_back(nSysWorks);

Here is the output:

Key: 5
Name: Adobe Photoshop
Version: CS5
Quantity: 21
Price: $580

Key: 1
Name: lities
Version: n/a
Quantity: 10
Price: $50


Key: 3
Name: System Works
Version: 2009
Quantity: 6
Price: $50


Key: 4
Name: al Studio Professional
Version: 2010
Quantity: 19
Price: $700

I tried cin.ignore() to try to get the rest of the titles that were truncated and also cin.clear() and you can probably guess that it just made things worse. I understand this is pretty basic stuff.Thank you for helping me over this hump.

bethm
  • 1
  • 8
  • 1
    I think your original problem is this [Why does std::getline() skip input after a formatted extraction?](https://stackoverflow.com/questions/21567291/why-does-stdgetline-skip-input-after-a-formatted-extraction) Unfortunately [Using `seekg` on a text-mode file](https://stackoverflow.com/questions/27055771/using-seekg-in-text-mode) has its own problems, so it is not a solution. – Bo Persson Nov 20 '17 at 15:30
  • OK so this is not helpful at all. – bethm Nov 20 '17 at 22:14
  • So is this example https://stackoverflow.com/a/10553849/597607 helping you see where the problem is? – Bo Persson Nov 20 '17 at 22:21
  • OK thanks for your feedback. I do appreciate any attempts to help me;) Unfortunately I already tried these things. – bethm Nov 21 '17 at 13:17

1 Answers1

0

Mixing getline and >> often goes bad as you need to be careful about newlines.
Using seekg on text files is also opening a huge can of worms, and it looks like you only stumbled across it.

Instead, stick to getline and use a std::istringstream on lines with multiple items:

getline(file, n);
getline(file, v);
std::string kqpline;
getline(file, kqpline);
std::istringstream kqpstream(kqpline);
kqpstream >> k >> q >> p;
pshop.setItem(k, n, v, q, p);

And you should abstract this out into a function.
This should work as-is:

ItemClass readItem(std::istream& in)
{
    std::string name;
    std::string version;
    std::getline(in, name);
    std::getline(in, version);
    std::string line;
    std::getline(in, line);
    std::istringstream data(line);
    // Just guessing on the types here.
    // Adjust according to reality.
    unsigned int key = 0;
    unsigned int quantity = 0;
    float price = 0;
    data >> key >> quantity >> price;
    ItemClass result;
    result.setItem(key, name, version, quantity, price);
    return result;
}

int main()
{    
    //declare a vector to hold the objects for later sorting and placing into a tree structure
    vector<ItemClass> classVector;
    ifstream file("software.txt");

    if (file.fail()) {
        cout << "Error reading from file." << endl;
        return -1;
    }

    ItemClass pshop = readItem(file);
    ItemClass nU = readItem(file);
    ItemClass sW = readItem(file);
    ItemClass vsP = readItem(file);
    cout << "here is the object we extracted from 'file': " << endl;
    pshop.printItem();
    nU.printItem();
    sW.printItem();
    vsP.printItem();

    classVector.push_back(pshop);
    classVector.push_back(nortonU);
    classVector.push_back(vsPro);
    classVector.push_back(nSysWorks);
}

(There's no error handling in this code since that would mostly be distracting. Real code should handle errors.)

molbdnilo
  • 55,783
  • 3
  • 31
  • 71
  • Thank you very much! So maybe I have this setup incorrectly, but I'm still getting unexpected output after my edits. I've updated the code above. – bethm Nov 20 '17 at 21:18
  • OK I finally got the code updated above to show what I've done //see note// Now I am getting the names of the softwares in the right spot, as well as the version info is also correct, but the quantity, price and keys all belong to the first record in the file. I also tried resetting the n, v, etc vars to see if that helped but it didn't. Thank you anyone who can help me through this..... – bethm Nov 20 '17 at 22:18
  • You never reset the `stringstream` to the next line. I've added a suggestion on how to structure this so you don't need to rely so heavily on copy and paste. – molbdnilo Nov 21 '17 at 06:33
  • Awesome. Working on it. Will report back. – bethm Nov 21 '17 at 20:55
  • OK I could never get this to work. I just thought I would let you know. I tried formatting my reads in main and in the class definition. I ended up cobbling together the output by subtracting from file marker: i.e., seekg(mark-7). – bethm Nov 22 '17 at 14:33
  • The code in this answer should work without modification if you remove all reading from `main` and the class definition. I've posted an update with a program that should work as it is. – molbdnilo Nov 22 '17 at 15:00
  • Well, this is a really stupid question, but I don't know how to declare the function-- or call if for that matter when it returns an object. I've created a gist on github so we might possibly go offline somewhat. Here is the address: https://gist.github.com/beth-o/3ff292ef1e5b31e88d4b136bc4d351b8 – bethm Nov 23 '17 at 22:15
  • Did you try to just use the code in the answer? Don't add your own around it. Don't rewrite as member functions. Copy. Paste. – molbdnilo Nov 24 '17 at 05:38
  • Glory be it works! I'm trying to mark your answer as accepted but the check mark isn't rendering. I'll figure it out and mark the question. I am so happy. Thanks. – bethm Nov 24 '17 at 14:51