By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,276 Members | 1,494 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,276 IT Pros & Developers. It's quick & easy.

classes wrting/reading to binary file

P: n/a
Hi all,

[code snippet appended at the end.)
my question:
A class has a few string variables with not know length at design
time.

Now I declare lets say a 1000 of those classes and put them in a vector.

Can I write that vector directly to a binary file?
(.wright((char *)&vector,sizeof (vector)))

Currently I write the classes to the file (iterate over the vector).
As a safety I write the length of the variable strings before the class
so that when I read the file I can create a string thats large enough,
using: .resize(length_of_string,'\0')

The code that I wrote works. If I leave a function out namely
files.clear();Could someone explain why it breaks?
Improvement on the code itself is always welcome.

My system:Linux 2.6 gnu compiler.
This is the code snipped that I wrote:
FileDes is the class with three strings (declared as "string")
the normal members functions are present get*data*, set*data*, operator<*>,...

ItsFile is declared as fstream in the class datafile (again a class with
normal member functions.)

void
datafile::ReadFromFile (vector < FileDes > &vecfd)
{
FileStatus (input, open); // opens a file in binary mode for input
int length, a, b, c;
//read the size of the vector.
//why? so only one (re)allocation is needed
ItsFile.read ((char *) &length, sizeof length);
vecfd.reserve (length);
for (int i = 0; i < length; i++) //reading from a file
{

//read the length of the 3 strings first:
ItsFile.read ((char *) &a, sizeof a);
ItsFile.read ((char *) &b, sizeof b);
ItsFile.read ((char *) &c, sizeof c);
FileDes temp(a,b,c) ; //expand strings to hold enough data
FileDes temp; //works also. does string expand automatically
//in this situation(or code)

//read the class and add to the vector
ItsFile.read ((char *) &temp, sizeof temp);

//if the program breaks it happens on the next line:
vecfd.push_back (temp);

}

}

int
main ()
{
datafile Filed;
int length;
vector < FileDes > files;
vector< FileDes > filesa;
Filed.GetFileList (files);
Filed.WriteToFile (files);
//The above all works fine checked it with displaying the strings when
//I knew what it had to contain

files.clear();//if left out the program works.
//if present it breaks at run time,
// executing the next line of code.
//break point in void datafile::ReadFromFile... at vecfd.push_back (temp);

Filed.ReadFromFile (filesa);

/*

DO SOME STUFF
*/
return 0;
}
Jul 22 '05 #1
Share this Question
Share on Google+
4 Replies


P: n/a
On Thu, 01 Jan 2004 07:52:26 +0000, nightflyer wrote:
Hi all,

[code snippet appended at the end.)
my question:
A class has a few string variables with not know length at design
time.

Now I declare lets say a 1000 of those classes and put them in a vector.

Can I write that vector directly to a binary file?
(.wright((char *)&vector,sizeof (vector)))


No, and this seems also to be why your program breaks. It seems you try
to modify string objects directly or something like that. You cannot just
stream out a class and hope it works. It doesn't. It only works for PODs
(search google on that) and then only if the POD does not contain
pointers. Both the string and the vector class break both rules.

Besides, even for the cases where it does work, it only works when the
receiver has the same binary layout as the sender. This often is not very
important, but it becomes /very/ important when this problem occurs on a
network connection. Same problem, different context only.

What you have to do is what you already did for the vector class. Stream
out using your own data format. A text-only format often works very well
(diskspace is cheap) and is very practical. But binary is possible as well
and much easier to program.

[ As an aside, you may want to take a look at XML libraries, they simplify
these kind of problems considerably, if at the price of a steep learning
curve. ]

Streaming out a string could be done something like this (errorchecking
omitted):

void so(std::ostream o, const std::string &s) {
size_t len = s.size();
o.write(reinterpret_cast<const char *>(&len), sizeof(len));
o.write(s.c_str(), len);
}

Reading back in is slightly trickier, we are not allowed to modify what
c_str() points to, nor can we assume safely we can use &s[0] as a pointer
to a continous array, so we use an intermediary to hold the contents of
the string:

void si(std::istream i, std::string &s) {
size_t len;
i.read(reinterpret_cast<const char *>(&len), sizeof(len));
vector<char> v(len);
i.read(&v[0], len);
s = string(v.begin(), v.end());
}

This code is untested, may contain bugs, may contain big errors. But you
probably get the basic idea.

It also might be a good idea to insert some markers in the stream for
better error checking. A magic number (signature) and version at the start
of the file are probable the least, but also sufficient for your problem.
When reading the file back, you check to see if the magic number is there
(high probablility the file was actually written by your program) and
check the version number (what version of the data-layout in the file are
we using, don't use program version number here).

HTH,
M4

Jul 22 '05 #2

P: n/a
On Thu, 01 Jan 2004 15:24:52 +0100, Martijn Lievaart wrote:
void so(std::ostream o, const std::string &s) {
void so(std::ostream & o, const std::string &s) {
void si(std::istream i, std::string &s) {


void si(std::istream & i, std::string &s) {

Oops.

M4

Jul 22 '05 #3

P: n/a
On Thu, 01 Jan 2004 16:06:29 +0100, Martijn Lievaart wrote:
On Thu, 01 Jan 2004 15:24:52 +0100, Martijn Lievaart wrote:
void so(std::ostream o, const std::string &s) {


void so(std::ostream & o, const std::string &s) {
void si(std::istream i, std::string &s) {


void si(std::istream & i, std::string &s) {

Oops.

M4


In void si(...):
i.read(reinterpret_cast<const char *>(&len), sizeof(len));

change to:
i.read(reinterpret_cast< char *>(&len), sizeof(len));

know it works.
thanks a lot for the help.
Jul 22 '05 #4

P: n/a
On Thu, 01 Jan 2004 19:46:25 +0000, nightflyer wrote:
In void si(...):
i.read(reinterpret_cast<const char *>(&len), sizeof(len));

change to:
i.read(reinterpret_cast< char *>(&len), sizeof(len));


Ahhh, damn! Next time I'll compile the stuff first.... :-)

Glad to be of service.

M4

Jul 22 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.