views:

592

answers:

4

Every time I do anything, and my while(1) gets called in my main function, my file gets cleared. It's driving me crazy. I've tried EVERYTHING. I try to put my ofstream out("data.dat"); outside the while(1) statement so it isn't called everytime but then nothing is written to the file like the ofstream isn't even working!

I've tried to make the ofstream static, so it isn't called over and over again like:

static ofstream open("data.dat");

That doesn't work.

And like I said, when I put the ofstream OUTSIDE the while statement, nothing is written to the file. Like:

ofstream out("data.dat");

    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");

     switch (rValue)
     {
      case 1:
       structList = addItem(structList);
       break;
      case 2:
       displayRecord(structList);
       break;
      case 3:
       structList = editRecord(structList);
       break;
      case 4:
       deleteRecord(structList);
       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();
    }

And can someone tell me why my check to prevent reading of a empty file won't work?

My Check:

bool checkFileEmpty()
{
    ifstream in("data.dat");

    if (in.peek() == in.eofbit)
    {
     return true;
    }

    return false;
}

I am so sick and tired of my program crashing on startup over and over again because my vector is getting set to a size of 200 million. I've tried a BUNCH of stuff for this... none of it works... Please GOD someone help me with both of these! I've been up for 18 hours working on this ( all night yes ) and i'm ALMOST done. I'm begging you....

My 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);

bool checkFileEmpty();

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);

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

template<typename T>
vector<T> deleteRecord(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:
       structList = addItem(structList);
       break;
      case 2:
       displayRecord(structList);
       break;
      case 3:
       structList = editRecord(structList);
       break;
      case 4:
       deleteRecord(structList);
       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 (checkFileEmpty())
    {
     size = 0;
    } else {
     in >> size;
    }

    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());

      choice -= 1;

      if (isValidChoice(size, choice))
      {
       system("cls");
       cout << endl << "[Item (" << choice << ") details] " << endl << endl;
       cout << "******************" << endl;
       cout << "*  Description   * " << vec[choice].Description << endl;
       cout << "******************" << endl << endl;
       cout << "******************" << endl;
       cout << "*Quantity On Hand* " << vec[choice].Quantity << endl;
       cout << "******************" << endl << endl;
       cout << "******************" << endl;
       cout << "* Wholesale Cost * " << vec[choice].wholesaleCost << endl;
       cout << "****************** " << endl << endl;
       cout << "******************" << endl;
       cout << "*  Retail Cost   * " << vec[choice].retailCost << endl;
       cout << "****************** " << endl << endl;
       cout << "******************" << endl;
       cout << "*  Data Added    * " << vec[choice].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 == i) { return true; }
    }
    return false;
}

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

    return word;
}

bool checkFileEmpty()
{
    ifstream in("data.dat");

    if (in.peek() == in.eofbit)
    {
     return true;
    }

    return false;
}

template<typename T>
vector<T> editRecord(vector<T> &vec)
{
    string word;
    int choice;
    printItemDescriptions(vec);

    cout << "Choose item to edit: ";
    getline ( cin, word );
    choice = atoi(word.c_str());


    system("cls");

    unsigned int number;

    InventoryItem newItem;

    cout << "-Edit an item-" << endl << endl;
    cout << "Enter the description for the item: ";
    getline (cin , word);
    vec[choice-1].Description = word;

    cout << endl;
    cout << "Enter the quantity on hand for the item: ";
    getline (cin , word);
    number = atoi(word.c_str());
    vec[choice-1].Quantity = number;

    cout << endl;
    cout << "Enter the Retail Cost for the item: ";
    getline (cin , word);
    number = atoi(word.c_str());
    vec[choice-1].retailCost = number;

    cout << endl;
    cout << "Enter the Wholesale Cost for the item: ";
    getline (cin , word);
    number = atoi(word.c_str());
    vec[choice-1].wholesaleCost = number;

    cout << endl;
    cout << "Enter current date: ";
    getline (cin , word);
    vec[choice-1].dateAdded = word;

    system("cls");

    cout << "Item edited successfully! " << endl;

    return vec;
}

template<typename T>
vector<T> deleteRecord(vector<T> &vec)
{
    if (!vec.size()) { cout << "There are no items to delete!" << endl << endl; return vec; }
    printItemDescriptions(vec);

    string word;
    int choice;

    cout << "Choose item to delete: ";

    getline( cin, word);

    choice = atoi(word.c_str());

    vec.erase (vec.begin()+choice-1);
    return vec;
}
+1  A: 
ofstream out("data.dat");

Opens the file for writing. By default, it will start at the very beginning wiping out anything that was there previously. First, use a different output file than the file you are reading from.

dirkgently
Would you mind elaborating a bit ?
OneShot
A: 

Try adding the close to the case 6 statements:

case 6:
        out.close();
        return 0;

I'm pretty sure the close isn't getting called as the return will exit main before getting to that statement. With the file unclosed you are left with a buffer unflushed and I suspect that will leave the data unwritten.

You should move the open to before the while loop and also remove the out.close() from the while loop as it's going to close the file after the first menu selection.

Lazarus
Well. I see what you are saying. I added that. But that won't fix the part where my file gets wiped every time I select a menu item.
OneShot
You could add ios::app to the open to ensure it appends, i.e. ofstream out("data.dat", ios::app);Also by moving the open to outside of the while it'll only get opened once and closed once, it won't keep overwriting.
Lazarus
out.close() will be called in out's destructor.
Richard Wolf
Thats what my whole question is based off of. When I move my open outside my while, it doesn't work anymore. Whenever I do save nothing is written to the file!
OneShot
A: 

To check if a file is empty or cannot be opened

bool IsEmpty( const std::string & filename ) {

   std::ifstream ifs( filename.c_str() );

   if ( ifs.is_open() ) {
      std::string line;
      return ! std::getline( ifs, line );
   }
   else {
      return true;
   }
}
anon
I tried what you said. I still get crash on program load because my Vector is set to 200 million... for some reason it isn't stopping size from getting set.
OneShot
NEVERMIND. I just got it to work. THANK YOU. Wow you are a freaking genius.
OneShot
+2  A: 

You'd better move the ofstream openning and closing inside case 5.

Here you create a new file at each while iteration.

case 5:
        {
            ofstream out("data.dat");
            writeVector(out , structList);
            out.close();
        }
        break;
fa.
I tried that I get this error: 1>.\Project 5.cpp(103) : error C2360: initialization of 'out' is skipped by 'case' label
OneShot
What's on line 105? I suspect it's the other close which you need to remove (and remove the initial open (constructor) as well). Voting up since this is better than my solution - you should only open the file for as long as you need it.
paxdiablo
OMG. It was this case 5:{ } the curly brackets that allowed me to create a ofstream. I never even knew you could do that. THANK YOU.
OneShot
{} are also often usefull to reduce local variables scoping, here they are needed to allow the variable declaration inside the case statement.
fa.