Connecting Tech Pros Worldwide Forums | Help | Site Map

Loading/Saving a structure using <fstream>

adamrobillard@gmail.com
Guest
 
Posts: n/a
#1: Dec 1 '05
Hi,

I have always used fopen and FILE* to load and save structures to file.
I am trying to convert all the older code to use proper C++ calls...
the following code works properly but I would like to know if I am
using the fstream methods properly. (as long as I am cleaning up I
might as well do it right). By the way, this is just a bogus example
with a structure, values and filename for demonstration purposes.

PS-> I have a funny feeling casting my structure to a char* is the
wrong approach! :)

#include <iostream>
#include <fstream>

struct stAnything
{
int nInteger;
long lLong;
char cChar;
double dDouble;
};

int main(void)
{
std::string sFilename = "C:/test.bin";
stAnything stSomeStructure;

stSomeStructure.nInteger = 5; // bogus values
stSomeStructure.lLong = 10;
stSomeStructure.cChar = 'A';
stSomeStructure.dDouble = 5.1;

// Save the structure to a binary file
std::ofstream outFile;
outFile.open(sFilename.c_str(), std::ofstream::out |
std::ofstream::binary);
if (!outFile.is_open())
{
std::cout << "Could not open the file for output." << std::endl;
return 1;
}
outFile.write((const char *) &stSomeStructure, sizeof(stAnything));
outFile.close();

// Clear the structure
stSomeStructure.nInteger = 0;
stSomeStructure.lLong = 0;
stSomeStructure.cChar = ' ';
stSomeStructure.dDouble = 0.0;

// Load the structure from a binary file
std::ifstream inFile;
inFile.open(sFilename.c_str(), std::ofstream::in |
std::ofstream::binary);
if (!inFile.is_open())
{
std::cout << "Could not open the file for input." << std::endl;
return 1;
}
inFile.read((char *) &stSomeStructure, sizeof(stAnything));
inFile.close();

// Show the loaded contents
std::cout << "{" << stSomeStructure.nInteger << ", " <<
stSomeStructure.lLong << ", " <<
stSomeStructure.cChar << ", " <<
stSomeStructure.dDouble << "} " << std::endl;
return 0;
}


Neil Cerutti
Guest
 
Posts: n/a
#2: Dec 1 '05

re: Loading/Saving a structure using <fstream>


On 2005-12-01, adamrobillard@gmail.com <adamrobillard@gmail.com> wrote:[color=blue]
> I have always used fopen and FILE* to load and save structures
> to file.[/color]

The approach has the same drawbacks in C++ as it did in C. It's
not portable. It won't work at all for structs that aren't Plain
Old Data types.
[color=blue]
> I am trying to convert all the older code to use proper C++
> calls...[/color]

I'm not sure it's really an improvement over the original C.

You may want to read about serialization. Reading and writing
your structs as plain old text won't be as compact, but it's
quite portable, and gives clients the benefit of human-readable
data files.
[color=blue]
> the following code works properly but I would like to know if I
> am using the fstream methods properly. (as long as I am
> cleaning up I might as well do it right). By the way, this is
> just a bogus example with a structure, values and filename for
> demonstration purposes.
>
> PS-> I have a funny feeling casting my structure to a char* is
> the wrong approach! :)[/color]

It's normally a bad idea. In this case, it's doesn't make your
code any less portable. But prefer C++ style casts intead of the
C-style cast used.
[color=blue]
> outFile.write((const char *) &stSomeStructure, sizeof(stAnything));[/color]

outFile.write(reinterpret_cast<const char *>(&stSomeStructure)
, sizeof(stAnything));

--
Neil Cerutti
mlimber
Guest
 
Posts: n/a
#3: Dec 1 '05

re: Loading/Saving a structure using <fstream>


adamrobillard@gmail.com wrote:[color=blue]
> Hi,
>
> I have always used fopen and FILE* to load and save structures to file.
> I am trying to convert all the older code to use proper C++ calls...
> the following code works properly but I would like to know if I am
> using the fstream methods properly. (as long as I am cleaning up I
> might as well do it right). By the way, this is just a bogus example
> with a structure, values and filename for demonstration purposes.[/color]

See the FAQ for more robust techniques that will work with all classes
and structs not just ones without virtual functions or, e.g.,
std::vectors:

http://www.parashift.com/c++-faq-lit...alization.html

And check out Boost's serialization library:

http://boost.org/libs/serialization/doc/index.html
[color=blue]
> PS-> I have a funny feeling casting my structure to a char* is the
> wrong approach! :)[/color]

For binary mode, you'll have to do that cast eventually.
[color=blue]
> #include <iostream>
> #include <fstream>
>
> struct stAnything
> {
> int nInteger;
> long lLong;
> char cChar;
> double dDouble;
> };
>
> int main(void)[/color]

Using void like that is an "abomination"
(http://www.research.att.com/~bs/sibling_rivalry.pdf).
[color=blue]
> {
> std::string sFilename = "C:/test.bin";[/color]

Should be const.
[color=blue]
> stAnything stSomeStructure;
>
> stSomeStructure.nInteger = 5; // bogus values
> stSomeStructure.lLong = 10;
> stSomeStructure.cChar = 'A';
> stSomeStructure.dDouble = 5.1;
>
> // Save the structure to a binary file
> std::ofstream outFile;
> outFile.open(sFilename.c_str(), std::ofstream::out |
> std::ofstream::binary);[/color]

Prefer to open and close with the constructor and destructor,
respectively, unless you need to do differently. (In this test program,
you would actually need to close the output file manually or else move
the serialization to a separate function so the file is closed via the
destructor when the function returns.)
[color=blue]
> if (!outFile.is_open())[/color]

Better would be:

if( !outFile )
[color=blue]
> {
> std::cout << "Could not open the file for output." << std::endl;
> return 1;
> }
> outFile.write((const char *) &stSomeStructure, sizeof(stAnything));[/color]

You didn't check that the write succeeded, and you should use C++-style
casts - reinterpret_cast would be appropriate here to signal a
potentially shady conversion.

Similar comments apply to the read portion.
[color=blue]
> outFile.close();
>
> // Clear the structure
> stSomeStructure.nInteger = 0;
> stSomeStructure.lLong = 0;
> stSomeStructure.cChar = ' ';
> stSomeStructure.dDouble = 0.0;
>
> // Load the structure from a binary file
> std::ifstream inFile;
> inFile.open(sFilename.c_str(), std::ofstream::in |
> std::ofstream::binary);
> if (!inFile.is_open())
> {
> std::cout << "Could not open the file for input." << std::endl;
> return 1;
> }
> inFile.read((char *) &stSomeStructure, sizeof(stAnything));
> inFile.close();
>
> // Show the loaded contents
> std::cout << "{" << stSomeStructure.nInteger << ", " <<
> stSomeStructure.lLong << ", " <<
> stSomeStructure.cChar << ", " <<
> stSomeStructure.dDouble << "} " << std::endl;
> return 0;
> }[/color]

You might also be interested in this section of the FAQ:

http://www.parashift.com/c++-faq-lite/input-output.html

Cheers! --M

Marcus Kwok
Guest
 
Posts: n/a
#4: Dec 1 '05

re: Loading/Saving a structure using <fstream>


mlimber <mlimber@gmail.com> wrote:[color=blue]
> adamrobillard@gmail.com wrote:[color=green]
>> // Save the structure to a binary file
>> std::ofstream outFile;
>> outFile.open(sFilename.c_str(), std::ofstream::out |
>> std::ofstream::binary);[/color]
>
> Prefer to open and close with the constructor and destructor,
> respectively, unless you need to do differently. (In this test program,
> you would actually need to close the output file manually or else move
> the serialization to a separate function so the file is closed via the
> destructor when the function returns.)[/color]

Alternately, he could wrap the code that uses outFile in an extra set of
{ }'s to limit its scope:

// ...
stSomeStructure.dDouble = 5.1;

{
// Save the structure to a binary file
std::ofstream outFile(sFilename.c_str(),
std::ofstream::out | std::ofstream::binary);
if (!outFile)
{
std::cout << "Could not open the file for output." << std::endl;
return 1;
}
outFile.write((const char *) &stSomeStructure, sizeof(stAnything));
}

// rest of code


--
SLuGHEAd78 | "Today, if you are not confused, you are
A.K.A. DJ Slant Eye, Chudmuffin, | just not thinking clearly."
Marcus Kwok, Silly Chink, Nuprin | -U. Peter
adamrobillard@gmail.com
Guest
 
Posts: n/a
#5: Dec 1 '05

re: Loading/Saving a structure using <fstream>


Thanks for all the suggestions... they seem to do the trick.

Closed Thread