Topic: Binary mode file I/O


Author: "Edward Diener" <eldiener@earthlink.net>
Date: 11 Dec 2002 05:56:43 -0500
Raw View
"Jim Gordon" <icodeREMOVE_THIS@twcny.rr.com> wrote in message
news:grAI9.15314$HA2.4195548@twister.nyroc.rr.com...
> I was told a day or so ago that writing an object to a file in binary mode
> also stores the memory addresses of the object members in the file. So the
> successfull read of the data is not reliable because the memory specified
in
> the file may be already used....
> ________________________________________________
> -----
> ofstream fout;
> fout.open("file.bin",ios_base::binary);
> assert(fout.is_open());
> fout.write(reinterpret_cast<char*>(myClass),sizeof(MyClass));

I assume that myClass is a pointer to an object of MyClass class type. The
C++ standard determines nothing about the data layout of such an object so
attempting to write out the data of the object as a whole and read it back
in again in the same way is totally implementation dependent. Because of
that it is completely non-portable. A much better way of writing out the
data of an object and reading it back in again is to do so for each data
member of the object. Even there, because you are writing out the binary
representation of the object, it will be non-portable to other operating
systems and even other implementations on the same operating system, but at
least it should work reliably for the implementation with which you are
working. The most portable way is to write out each data member as a string
of characters separated from the next data member by one or more spaces
using stream << notation and read each data member back ing using stream >>
notation.

> fout.close();
> -----
> ________________________________________________
> Now let's say the file is stored on the computer, and a few days go by and
> the file is read...
> __________________________________________________
> -----
> ifstream fin;
> fin.open("file.bin",ios_base::binary);
> assert(fin.is_open());
> fin.read(reinterpret_cast<char*>(myClass),sizeof(MyClass));
> fin.close()
> -----
> ___________________________________________________
> So my question is, "Is there any chance that the read will fail as
described
> above?". I have used this technique many times to read and write object
data
> to files and don't remember ever having any trouble. I have searched
through
> my books and on the net and found nothing to confirm this behavior of
> reading and writing files in binary mode. Respond with any info you may
> have - opinions, links, etc.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: allan_w@my-dejanews.com (Allan W)
Date: 11 Dec 2002 05:57:22 -0500
Raw View
"Jim Gordon" <icodeREMOVE_THIS@twcny.rr.com> wrote
> I was told a day or so ago that writing an object to a file in binary mode
> also stores the memory addresses of the object members in the file.

No, of course not.

> So my question is, "Is there any chance that the read will fail as described
> above?".

Well, yes. It's different when one of the object members is a pointer or
reference. If it's a pointer, you write the value of that pointer to the
file, which is rarely what you want. If it's a reference, you write the
binary contents of whatever the compiler uses to implement the reference,
which typically is the address of the referent.

So whoever told you this might not have been joking; they may simply
have observed that your "myclass" data has a pointer or reference (or
an object that itself contains a pointer or reference, such as a
vector or string).

    class class1 {
        int a, b, c;
        double d;
        char name[32];
    public:
        // This won't work right with derived classes...
        void writeto(FILE*out) const { out.write(this, sizeof(*this)); }
    }; // No problem

    class class2 {
        int a, b, c;
        double d;
        std::string name[32]; // This is very different
    public:
        // This won't work right ever...
        void writeto(FILE*out) const { out.write(this, sizeof(*this)); }
    }; // Uh oh!

class2::writeto() will write 3 ints, 1 double, and a string. The size of
a string object is always fixed, typically at about
sizeof(char*)+sizeof(int), regardless of the length of the string --
the actual string contents are on the heap somewhere, and string contains
only the address of that heap allocation. So std::string cannot be
written and read back this way.

> I have used this technique many times to read and write object data
> to files and don't remember ever having any trouble.

And you won't have trouble, so long as your classes don't contain any
references or pointers, directly or indirectly.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: rmaddox@isicns.com (Randy Maddox)
Date: 11 Dec 2002 09:09:32 -0500
Raw View
"Jim Gordon" <icodeREMOVE_THIS@twcny.rr.com> wrote in message news:<grAI9.15314$HA2.4195548@twister.nyroc.rr.com>...
> I was told a day or so ago that writing an object to a file in binary mode
> also stores the memory addresses of the object members in the file. So the
> successfull read of the data is not reliable because the memory specified in
> the file may be already used....
> ________________________________________________
> -----
> ofstream fout;
> fout.open("file.bin",ios_base::binary);
> assert(fout.is_open());
> fout.write(reinterpret_cast<char*>(myClass),sizeof(MyClass));
> fout.close();
> -----
> ________________________________________________
> Now let's say the file is stored on the computer, and a few days go by and
> the file is read...
> __________________________________________________
> -----
> ifstream fin;
> fin.open("file.bin",ios_base::binary);
> assert(fin.is_open());
> fin.read(reinterpret_cast<char*>(myClass),sizeof(MyClass));
> fin.close()
> -----
> ___________________________________________________
> So my question is, "Is there any chance that the read will fail as described
> above?". I have used this technique many times to read and write object data
> to files and don't remember ever having any trouble. I have searched through
> my books and on the net and found nothing to confirm this behavior of
> reading and writing files in binary mode. Respond with any info you may
> have - opinions, links, etc.
> -----Jim G.

As long as the bytes written to/read from the file contain the entire
state of the object, then you are somewhat safe doing this.  Assume,
however, that myClass has a data member of type std::string, which
internally has a pointer to some memory where the actual string
contents are stored.  You write out your myClass object to a file,
which using the code above merely writes out the internal data members
of the std::string, but which does NOT write out the actual string
contents.  Now you later read back in your myObject, which restores
the internal data members of the std::string, i.e., now the
std::string believes that the memory addressed by its internal pointer
still points to the same string contents.  How likely is that to be
true?

Any object that contains a pointer or reference cannot be safely
written to a file and read back using this technique.  Other resources
can cause similar problems.  What if your object has a window handle,
file handle, mutex, or any other system resource.  When you simply
read back in the previous value of that resource handle how likely is
it to be valid?  Not bloody likely in almost every case.

Randy.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.de (James Kanze)
Date: 11 Dec 2002 09:09:50 -0500
Raw View
"Jim Gordon" <icodeREMOVE_THIS@twcny.rr.com> wrote in message
news:<grAI9.15314$HA2.4195548@twister.nyroc.rr.com>...

> I was told a day or so ago that writing an object to a file in binary
> mode also stores the memory addresses of the object members in the
> file. So the successfull read of the data is not reliable because the
> memory specified in the file may be already used....

It has nothing to do with the memory specified in the file being used.

> ________________________________________________
> -----
> ofstream fout;
> fout.open("file.bin",ios_base::binary);
> assert(fout.is_open());
> fout.write(reinterpret_cast<char*>(myClass),sizeof(MyClass));
> fout.close();
> -----
> ________________________________________________
> Now let's say the file is stored on the computer, and a few days go by
> and the file is read...
> __________________________________________________
> -----
> ifstream fin;
> fin.open("file.bin",ios_base::binary);
> assert(fin.is_open());
> fin.read(reinterpret_cast<char*>(myClass),sizeof(MyClass));
> fin.close()
> -----
> ___________________________________________________

> So my question is, "Is there any chance that the read will fail as
> described above?".

Very definitely.  I WILL fail with most implementations if the class
uses virtual base classes.  If you are reading it into another program
(or simply the same program with some dynamically linked objects
incorporated differently), it WILL fail if the class contains any
virtual functions.  According to the standard, it MAY fail, same program
or not, unless the class is a PODS.

And of course, once you change the compiler version, or compiler with
other options, it is very likely to fail.

> I have used this technique many times to read and write object data to
> files and don't remember ever having any trouble.

Except when Microsoft changed the order of long's from one version to
the next?  Except when the class had virtual functions, and you relinked
the application?  Except...

> I have searched through my books and on the net and found nothing to
> confirm this behavior of reading and writing files in binary
> mode. Respond with any info you may have - opinions, links, etc.

It's something you should never do, except maybe for POD data written to
a temporary file which is only reread by the same execution of the
program (and deleted before exiting the program).

--
James Kanze                           mailto:jkanze@caicheuvreux.com
Conseils en informatique orient   e objet/
                    Beratung in objektorientierter Datenverarbeitung
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Jim Gordon" <icodeREMOVE_THIS@twcny.rr.com>
Date: 09 Dec 02 11:18:39 GMT
Raw View
I was told a day or so ago that writing an object to a file in binary mode
also stores the memory addresses of the object members in the file. So the
successfull read of the data is not reliable because the memory specified in
the file may be already used....
________________________________________________
-----
ofstream fout;
fout.open("file.bin",ios_base::binary);
assert(fout.is_open());
fout.write(reinterpret_cast<char*>(myClass),sizeof(MyClass));
fout.close();
-----
________________________________________________
Now let's say the file is stored on the computer, and a few days go by and
the file is read...
__________________________________________________
-----
ifstream fin;
fin.open("file.bin",ios_base::binary);
assert(fin.is_open());
fin.read(reinterpret_cast<char*>(myClass),sizeof(MyClass));
fin.close()
-----
___________________________________________________
So my question is, "Is there any chance that the read will fail as described
above?". I have used this technique many times to read and write object data
to files and don't remember ever having any trouble. I have searched through
my books and on the net and found nothing to confirm this behavior of
reading and writing files in binary mode. Respond with any info you may
have - opinions, links, etc.
-----Jim G.

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]




Author: Thomas Richter <thor@cleopatra.math.tu-berlin.de>
Date: 10 Dec 02 08:49:45 GMT
Raw View
In comp.lang.c++.moderated Jim Gordon <icodeREMOVE_THIS@twcny.rr.com> wrote:

Hi,

> I was told a day or so ago that writing an object to a file in binary mode
> also stores the memory addresses of the object members in the file.

No, the address of the object is not stored on disk. However, if you
keep pointers within the object, these are stored -- rather than the objects
pointed to. And this method is not endian-save, too. It might also include
the vtable for the object which cannot be savely restored just by reading
a binary.
      The output generated
by saving an object in binary format to disk depends on the machine you
compiled and executed the code on. About the only thing that can be stored
in a portable way would be "octets" (i.e. bytes) of eight bits. If portability
is not an issue, you should only write integral data types in binary format.
For everthing else, I'd recommend a "saveToFile" method for all your objects.
Then, when in need to put an object to disk, save all members to disk by
either writing them out in binary format if the data type is integral, or by
ivocing hts "saveToFile" method recursively.


> ifstream fin;
> fin.open("file.bin",ios_base::binary);
> assert(fin.is_open());
> fin.read(reinterpret_cast<char*>(myClass),sizeof(MyClass));
> fin.close()

> So my question is, "Is there any chance that the read will fail as described
> above?".

Yes. Don't do that. Objects should provide a "saving" method that stores
the required parts and enough information to restore its internal state.

> I have used this technique many times to read and write object data
> to files and don't remember ever having any trouble.

That very much depends on your objects. I wouldn't recommend this method.
About the best and most portable thing you could do is to generate a human-
readable text file encoding all the data within the object encoded in plain
ASCII. This will always work, regardless of the system. Writing out raw
objects does not only require the same hardware to recover the object contents,
it also requires the same compiler to be used on the code, as you also write
all "padding" bytes out, and the object layout must coincide, and...

So long,
 Thomas

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]