Re: Problem writing struct out to file
rmr531@gmail.com wrote:
First of all I am very new to c++ so please bear with me. I am trying
to create a program that keeps an inventory of items. I am trying to
use a struct to store a product name, purchase price, sell price, and
a taxable flag (a Y/N char) and then write this all out to a file
(preferably just a plain old text file) and then read it in later so
that I can keep a running inventory. The problem that I am running
into is when I write to the file it seems save it but when I read it
back in it doesn't seem to give me anything. From what I have been
able to figure out so far you can't just save a String to a file you
have to manipulate it somehow but being very new (and not that good)
at c++ I can't figure out a practical way to do it.
I presume that this is a school project, and not something that
will be actually used commercially. Otherwise, there are some
very serious problems.
Is there any simple way to handle this or might I be better off trying
to do it somehow other than a Struct?
Well, you already mentionned the best solution: plain old text.
But even with plain old text, you have to define a format.
(FWIW: since you're struct really just contains raw data, and
has no behavior, a struct seems perfectly appropriate. In a
real application, of course, you'd probably give it some
behavior, to ensure consistency between the various fields,
etc.)
This is what I have so far, tried to limit the code to what relates to
this problem so it might make a little more sense. If more is needed
will be happy to post.
*************************************
struct product
{
int stockNum;
string name;
float cost;
float price;
char tax;
};
First, as Alf said, make cost and price at least double. (In a
real application, it's more complicated, because of legally
imposed rounding rules which suppose a base 10 representation,
several different tax rates, etc., etc..)
The simplest solution (to implement) with regards to format is
to reserve a character as a field separator, say ':', and forbid
it in the name field, and put one record per line. So you'd end
up with something like:
std::ostream&
operator<<( std::ostream& dest, product const& source )
{
dest << stockNum << ':' << name << ':'
<< cost << ':' << price << ':' << tax << '\n' ;
return dest ;
}
Reading is a bit more complicated, because you have to do error
checking. In general, it's best to read line by line (in a line
oriented file, at least), since it allows easy resynchronization
in case of error, and also allows outputting a usable indication
of where the error occured (the line number). So you might end
up with something like:
std::istream&
operator>>( std::istream& source, product& dest )
{
std::string line ;
if ( getline( source, line ) ) {
parseLine( line, dest ) ;
}
return source ;
}
Parsing the line is pretty classical; you can use the individual
fields to initialize an std::istringstream to convert the
numeric values. (To do this, std::find and the two iterator
constructor of std::string seem indicated.)
product inventory[25];
Again, as Alf said, std::vector is a far better solution.
Until you know C++ fairly well, you shouldn't be using C style
arrays.
ofstream st("c:/stock.txt");
ifstream stI("c:/stock.txt");
stI.read((char *)&inventory, sizeof(inventory));
[...]
st.write((char *)&inventory, sizeof(inventory));
*********************************
And of course, all ostream::write and istream::read do is dump
and reload the memory. About the only time you use them is for
preformatted buffers. Like C style arrays, they're only for
programmers with a bit of experience. Globally, until you
understand a lot more about binary formats, etc., you should
only be using <<, >> and getline.
Using operators like the above, your code might become:
void
load( std::vector< product >& inventory )
{
std::ifstream file( "c:/stock.txt" ) ;
if ( ! file ) {
// Error handling, could not open...
// throw ... ?
}
std::copy( std::istream_iterator< product >( file ),
std::istream_iterator< product >(),
std::back_inserter( inventory ) ) ;
if ( ! file.eof() ) {
// Hard read error...
}
}
void
store( std::vector< product > const& inventory )
{
rename( "c:/stock.txt", "c:/stock.bak" ) ;
std::ofstream file( "c:/stock.txt" ) ;
std::copy( inventory.begin(), inventory.end(),
std::ostream_iterator< product >( file ) ) ;
file.close() ;
if ( ! file ) {
// Oops! Problem writing the data to disk.
// delete "c:/stock.txt" ?
// throw ... ?
}
}
and in main...
std::vector< product > inventory ;
load( inventory ) ;
process( inventory ) ;
save( inventory ) ;
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34