views:

444

answers:

4

If I type in

Description: Apple

Quantity: 10

Wholesale Cost: 30

Retail Cost: 20

Date Added: December

These are the contents in my .dat file:

1Apple103020December

But when I load my program, it doesn't load the struct back in correctly resulting in there being 0 items in my list. Is that what it is suppose to look like or am I doing something seriously wrong.

Code:

#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

using namespace System;
using namespace std;
#pragma hdrstop

bool isValidChoice(int size, int choice);

template<typename T>
void writeVector(ofstream &out, const vector<T> &vec);

template<typename T>
vector<T> readVector(ifstream &in);

template<typename T>
vector<T> addItem(vector<T> &vec);

template<typename T>
void printItemDescriptions(vector<T> &vec);

template<typename T>
int displayRecord(vector<T> &vec);

struct InventoryItem {
    string Description;
    int Quantity;
    int wholesaleCost;
    int retailCost;
    string dateAdded;
} ;


int main(void)
{
    cout << "Welcome to the Inventory Manager extreme! [Version 1.0]" << endl;
    ifstream in("data.dat");
    if (in.is_open()) { cout << "File \'data.dat\' has been opened successfully." << endl; } else { cout << "Error opening data.dat" << endl;}
    cout << "Loading data..." << endl;
    vector<InventoryItem> structList = readVector<InventoryItem>( in );
    cout <<"Load complete." << endl << endl;
    in.close();


    while (1)
    {

     string line = "";
     cout << "There are currently " << structList.size() << " items in memory.";
     cout << endl << endl;
     cout << "Commands: " << endl;
     cout << "1: Add a new record " << endl;
     cout << "2: Display a record " << endl;
     cout << "3: Edit a current record " << endl;
     cout << "4: Delete a record " << endl;
     cout << "5: Save current information " << endl;
     cout << "6: Exit the program " << endl;
     cout << endl;
     cout << "Enter a command 1-6: ";

     getline(cin , line);

     int rValue = atoi(line.c_str());

     system("cls");

     ofstream out("data.dat");

     switch (rValue)
     {
      case 1:
       addItem(structList);
       break;
      case 2:
       displayRecord(structList);
       break;
      case 3:
       break;
      case 4:
       break;
      case 5:
       if (!structList.size()) { cout << "There are no items to save! Enter one first!" << endl << endl; system("pause"); system("cls"); break; }
       writeVector(out , structList);
       break;
      case 6:
       return 0;
      default:
       cout << "Command invalid. You can only enter a command number 1 - 6. Try again. " << endl;
     }

     out.close();
    }

    system("pause");

    return 0;
}

template<typename T>
void writeVector(ofstream &out, const vector<T> &vec)
{
    out << vec.size();

    for(vector<T>::const_iterator i = vec.begin(); i != vec.end(); i++)
    {
        out << *i;
    }
    cout << "Save completed!" << endl << endl;
}

ostream &operator<<(ostream &out, const InventoryItem &i)
{
    out << i.Description;
    out << i.Quantity;
    out << i.wholesaleCost << i.retailCost;
    out << i.dateAdded;
    return out;
}

istream &operator>>(istream &in, InventoryItem &i)
{
    in >> i.Description;
    in >> i.Quantity;
    in >> i.wholesaleCost >> i.retailCost;
    in >> i.dateAdded;
    return in;
}



template<typename T>
vector<T> readVector(ifstream &in)
{
    size_t size;
    if (in.fail())
    {
    in >> size;
    } else {
     size = 0;
    }

    vector<T> vec;
    vec.reserve(size);

    for(unsigned int i = 0; i < size; i++)
    {
        T tmp;
        in >> tmp;
        vec.push_back(tmp);
    }

    return vec;
}

template<typename T>
vector<T> addItem(vector<T> &vec)
{
    system("cls");

    string word;
    unsigned int number;

    InventoryItem newItem;

    cout << "-Add a new item-" << endl << endl;
    cout << "Enter the description for the item: ";
    getline (cin , word);
    newItem.Description = word;

    cout << endl;
    cout << "Enter the quantity on hand for the item: ";
    getline (cin , word);
    number = atoi(word.c_str());
    newItem.Quantity = number;

    cout << endl;
    cout << "Enter the Retail Cost for the item: ";
    getline (cin , word);
    number = atoi(word.c_str());
    newItem.retailCost = number;

    cout << endl;
    cout << "Enter the Wholesale Cost for the item: ";
    getline (cin , word);
    number = atoi(word.c_str());
    newItem.wholesaleCost = number;

    cout << endl;
    cout << "Enter current date: ";
    getline (cin , word);
    newItem.dateAdded = word;

    vec.push_back(newItem);

    return vec;
}

template<typename T>
void printItemDescriptions(vector<T> &vec)
{
    int size = vec.size();

    if (size)
    {
     cout << "---------------------------------" << endl;
     cout << "|      ~ Item Descriptions ~    |" << endl;
     cout << "---------------------------------" << endl;
     cout << "*********************************" << endl;
     for (int i = 0 ; i < size ; i++)
     {
      cout << "(" << i+1 << ")" << ": " << vec[i].Description << endl;
     }
     cout << "*********************************" << endl << endl;
    }
}

template<typename T>
int displayRecord(vector<T> &vec)
{
    string word = "";
    string quit = "quit";
    int choice = 1;
    int size = vec.size();

    if (size)
    {
     printItemDescriptions(vec);
     cout << endl;

     while (1)
     {
      cout << "Type \"exit\" to return to the Main Menu." << endl << endl;
      cout << "Enter \"list\" to re-display the items." << endl << endl;
      cout << endl;
      cout << "Pick the number of the item you would like to display: ";
      getline (cin , word);

      if (convertToLower(word) == "exit") { system("cls"); return 0; }
      if (convertToLower(word) == "list") { system("cls"); displayRecord(vec); }

      choice = atoi(word.c_str());

      if (isValidChoice(size, choice))
      {
       system("cls");
       cout << endl << "[Item (" << choice << ") details] " << endl << endl;
       cout << "******************" << endl;
       cout << "*  Description   * " << vec[choice-1].Description << endl;
       cout << "******************" << endl << endl;
       cout << "******************" << endl;
       cout << "*Quantity On Hand* " << vec[choice-1].Quantity << endl;
       cout << "******************" << endl << endl;
       cout << "******************" << endl;
       cout << "* Wholesale Cost * " << vec[choice-1].wholesaleCost << endl;
       cout << "****************** " << endl << endl;
       cout << "******************" << endl;
       cout << "*  Retail Cost   * " << vec[choice-1].retailCost << endl;
       cout << "****************** " << endl << endl;
       cout << "******************" << endl;
       cout << "*  Data Added    * " << vec[choice-1].dateAdded << endl;
       cout << "****************** " << endl << endl;
      } else { system("cls"); cout << "That item doesn't exist!" << endl; cout << "Pick another item or enter \"list\" to see available items." << endl << endl; }
     }
    } else { cout << "There are currently no items to display." << endl << endl; system("pause"); system("cls"); return 0; }

    return 1;
}

bool isValidChoice(int size, int choice)
{
    for (int i = 0 ; i <= size ; i++)
    {
     if (choice == size) { return true; }
    }
    return false;
}

string convertToLower(string word)
{
    for (unsigned int i = 0 ; i < word.size() ; i++)
    {
     word[i] = tolower(word[i]);
    }

    return word;
}
+3  A: 

In your read function:

   if (in.fail())

should be:

   if ( ! in.fail())

Or better:

int n;

if ( ! (in >> n) ) {
  n = 0;
}
anon
I did that once, and I was getting vector too large errors because my Vector was getting set to a size of over 20 million and stuff. How do I prevent it from setting a Vectors size if the file is blank?
OneShot
Yeah I did that, and I got a fatal error because Size was a couple of million. Fail is useless I guess right ?
OneShot
How does that work if you dont initialize N ?
OneShot
Why would you expect it not to work?
anon
I have no clue how this works.. but I think it does.
OneShot
+1  A: 

Use some separator for strucutre items, e.g. " " (space)

bb
Ummm I have no clue on how to go about doing that. I've been at this for hourssssss....
OneShot
can you provide an example on how to do that ?
OneShot
@cpitis already provided example=))
bb
+1  A: 

You need to add a blank (space/tab) between your strings when saving the DAT file.

When using operator>> to read strings, it will read a string until first blank character (space/tab/EOL) is found.

From your code:

ostream &operator<<(ostream &out, const InventoryItem &i)
{
    out << i.Description << ' ';
    out << i.Quantity << ' ';
    out << i.wholesaleCost  << ' ' << i.retailCost  << ' ';
    out << i.dateAdded  << ' ';
    return out;
}

Updated

Even so, when using operator>> to load description, for example, the description will be incomplete (loaded until the first space in the saved description text).

Cătălin Pitiș
So that right there will fix my load problem ? lol
OneShot
Well... if your description contains spaces... you'll still have problems loading... Because the description loading will be limited to the first one.For serialization/deserialization you need something more evolved, in my oppinion. See, for example Boost.Serialization.
Cătălin Pitiș
+1  A: 

Again, serialization is a not-so-simple task. If you can invest time in learning a library.

I am not going to repost the answer I gave to the previous question you made, but I believe you should really take a look at it. It explains some of the problems you are facing and provides a solution.

David Rodríguez - dribeas
Sorry. I did read your link. I'm just trying to get my project done so I can LOOK at it for a working reference that I can understand. I've been at this for 15 hours plus... so please understand why I had to ask so many questions here. I REALLY thank you so much for all the help you've given me.
OneShot
It's ok. I hope it helps you :)
David Rodríguez - dribeas