Is it possible to read data from a binary file to a C++ class using istream::read ? I know it can be done for structures, but I couldnt do it for a class.

[Edit]
Want code?

#include <iostream>
#include <fstream>

class BITMAPFILEHEADER
{
private:
    char                type[ 2 ];              // Magic identifier
    unsigned int        size;                   // File size in bytes
    unsigned short int  reserved1;              // Reserved; always zero
    unsigned short int  reserved2;              // Reserved; always zero
    unsigned int        offset;                 // Offset to image data, bytes

public:
    friend std::istream& operator>>(std::istream& s, BITMAPFILEHEADER& r);
};
std::istream& operator>>(std::istream& s, BITMAPFILEHEADER& r);
std::istream& operator>>(std::istream& s, BITMAPFILEHEADER& r)
{
#if 0
    // This does not work
    s.read( reinterpret_cast <char*>(&r), sizeof(BITMAPFILEHEADER) );
    if( s.bad() )
    {
        std::cerr << "Error reading data" << std::endl;
        exit( 0 );
    }
#endif
#if 1
     // This works
    s.read( r.type, 2 * sizeof(char) );
    if( s.bad() )
    {
        std::cerr << "Error reading data" << std::endl;
        exit( 0 );
    }

    s.read( (char*)&(r.size), sizeof(unsigned int) );
    if( s.bad() )
    {
        std::cerr << "Error reading data" << std::endl;
        exit( 0 );
    }

    s.read( (char*)&(r.reserved1), sizeof(unsigned short int) );
    if( s.bad() )
    {
        std::cerr << "Error reading data" << std::endl;
        exit( 0 );
    }

    s.read( (char*)&(r.reserved2), sizeof(unsigned short int) );
    if( s.bad() )
    {
        std::cerr << "Error reading data" << std::endl;
        exit( 0 );
    }

    s.read( (char*)&(r.offset), sizeof(unsigned int) );
    if( s.bad() )
    {
        std::cerr << "Error reading data" << std::endl;
        exit( 0 );
    }
#endif

    return s;
}

I think it is better to take the serialized approach you presented. Even with a POD structure the binary read/write is inherently non-portable.

Nit - consider this:

s.read( r.type, sizeof r.type );
//s.read( r.type, 2 * sizeof(char) );

// ...

s.read( (char*)&(r.size), sizeof r.size );
//s.read( (char*)&(r.size), sizeof(unsigned int) );

And FWIW:
http://www.parashift.com/c++-faq-lite/serialization.html#faq-36.6

sometimes in reading binary files, you may want take a byte of data and store it into something bigger. Then it is NOT good to use the sizeof( <class variable> ) to specify how much of the file to read. EX. what if you want to read 1 byte of the file into an" integer size" class variable, r::int var1? using the sizeof(r.var1) in the read statement would indicate that 4 bytes are to be read instead of just 1 byte. this will throw off the parsing of the file.

Comments
Correcting AD's positive rep
If it's not an int but a different object, then you use a different object (not an int) and you still use sizeof as I showed. And don't go gravedigging for dead threads.
partial correction for AD
Only four years too late!

This is your lucky day -- I gave you positive instead of negative rep for bumping a 4-year-old thread

If you only read one byte into a 4-byte integer that would make the integer not worth shit. You can't do it like that (at least so that it will produce a valid integer). First read the byte into a char variable, then typecast the char into the integer. The sizeof operator will still work because sizeof(char) = 1.

Edited 6 Years Ago by Ancient Dragon: n/a

This article has been dead for over six months. Start a new discussion instead.