views:

160

answers:

4

As most of you may be following my line of questions already know, i'm trying to create a program that can serialize multiple structs to a .dat file, read them back in via loading it's serialization, edit the contents, and then re-write them to the file and so on. It's a inventory program I am trying to do and I can't get it to work for the life of me.

The file i'm loading in, is blank. My program takes like 10 seconds to even load and now I know why. It's cause the size of my vector is like 250 thousand. Oh wait... this time I ran it the size of my vector was 5,172,285. Thats a pretty big vector full of structs. There aren't any run-time or compile errors, but I am pretty sure I am doing something wrong. The file i'm loading in is completely blank too.

Code:

// Project 5.cpp : main project file.

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

using namespace System;
using namespace std;
#pragma hdrstop

int checkCommand (string line);

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

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

struct InventoryItem {
    string Item;
    string Description;
    int Quantity;
    int wholesaleCost;
    int retailCost;
    int 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; return 0;}
    cout << "Loading data..." << endl;
    vector<InventoryItem> structList = readVector<InventoryItem>( in );
    cout <<"Load complete." << endl;

    while (1)
    {

     string line = "";
     cout << "There are currently " << structList.size() << " items in memory.";
     cout << 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: Exit the program " << endl;
     cout << endl;
     cout << "Enter a command 1-4: ";

     getline(cin , line);


     int rValue = checkCommand(line);
     if (rValue == 1)
     {
      cout << "You've entered a invalid command! Try Again." << endl;
     } else if (rValue == 2){ 
      cout << "Error calling command!" << endl;
     } else if (!rValue) {
      break;
     }
    }


    system("pause");

    return 0;
}

int checkCommand (string line)
{
    int intReturn = atoi(line.c_str());
    int status = 3;

    switch (intReturn)
    {
     case 1:
      break;
     case 2:
      break;
     case 3:
      break;
     case 4:
      status = 0;
      break;
     default:
      status = 1;
      break;
    }
    return status;
}

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

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

istream &operator>>(istream &in, InventoryItem &i)
{
    in >> i.Item >> 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;
    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;
}

Can someone simply show me how to turn this in to a program that can actually write serialized vectors full of structs to a file, and then read them back in so I can edit them and store them back for loading later? Oh my goodness what a ride this has been!

THANK YOU for any help you can provide!

+5  A: 

You say the file is actually empty. The first line in readVector is this:

in >> size;

What do you suppose is actually going to end up in size? Since it is empty, this will result in an error, which you aren't detecting. The variable size will remain uninitialised - hence you see weird values in it, since it takes whatever value happened to be in memory at that time. You can check the state of the stream by using the check:

if (in)

Treating it in boolean context tells you if an error occurred - this will also cover things like it being unable to read in a valid integer variable. I suggest you should figure out how to run your program in a debugger, you will be able to step through your code and see what the values of the variables are at a given time.

1800 INFORMATION
i tried if (in) { in >> size; } else { size = 0; }But i'm still getting the same problem. Was that the fix you suggested?
OneShot
Not exactly. The error state is set after you try to read from the stream, not before
1800 INFORMATION
Well what do you mean by that?
OneShot
To be more precise, after you have done the line `in >> size` (or attempted any other kind of read from the stream), the error state is set - you should check the state after each attempted read
1800 INFORMATION
+3  A: 

So if your file is blank and your doing:

size_t size;
in >> size;

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

What do you think will happen? Size cannot be read and uses a random value

PoweRoy
How do I prevent this from happening?
OneShot
See 1800 INFORMATION post and comments
PoweRoy
+3  A: 

If your input file is blank, then the vector should be empty. You shouldn't go past the line:

if (in.is_open())

-- your program (when I run it on my machine) quits.

Can you explain why you have the following?

#include <String>

using namespace System;

#pragma hdrstop

The easiest to implement is to read in the file contents in one go, keep the items in memory, edit them in-memory and write out to file once through with editing. This is of course not a very good technique from memory footprint or performance point of view. But then, the problem you are trying to solve is not trivial. Read FAQ 36 to gain a better understanding of your task.

dirkgently
OneShot
Ohhh crap. Thats because of the if(file.is_open) at the beginning of the file sorry
OneShot
A: 

You are using blank files, but when you go to load the file, you are looking for a size. When the file does not have a size in the file, you may be getting garbage into your size variable.

So trying putting a zero in the first line of the 'data.dat' file.

Edit: The above suggestion was just a temporary fix. You could try this:

in >> size;
//input operation failed
if(in.fail())
    //return, or whatever you need to do
Naxos
I don't think this can be quite right though, isn't it better to write the code in such a way that it can handle an empty file?
1800 INFORMATION
I agree. I was more suggesting it as a temporary fix... I should've mentioned that. Oops!
Naxos
How do I write code that prevents this though ?
OneShot
See my edit. It worked on my machine.
Naxos
Thank you that is what I was asking for. I added it and it worked.
OneShot