sign in | join about | help | sitemap
Connecting Tech Pros Worldwide
adamrobillard@gmail.com's Avatar

Loading/Saving a structure using <fstream>


Question posted by: adamrobillard@gmail.com (Guest) on December 1st, 2005 09:35 PM
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;
}

4 Answers Posted
Neil Cerutti's Avatar
Guest - n/a Posts
#2: Re: Loading/Saving a structure using <fstream>

On 2005-12-01, Join Bytes! <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's Avatar
Guest - n/a Posts
#3: Re: Loading/Saving a structure using <fstream>

Join Bytes! 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-li...ialization.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's Avatar
Guest - n/a Posts
#4: Re: Loading/Saving a structure using <fstream>

mlimber <mlimber@gmail.com> wrote:[color=blue]
> Join Bytes! 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's Avatar
adamrobillard@gmail.com December 1st, 2005 11:45 PM
Guest - n/a Posts
#5: Re: Loading/Saving a structure using <fstream>

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

 
Not the answer you were looking for? Post your question . . .
196,946 members ready to help you find a solution.
Join Bytes.com

What is Bytes?

We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights. Get the best answers to your questions from over 196,946 network members.
Post your question now . . .
It's fast and it's free

Popular Articles

Top Community Contributors