Clean binary stream

Discussion in 'C++' started by Michael, Jan 5, 2007.

  1. Michael

    Michael Guest

    I have a solution for this, but it feels wrong. If anyone could offer
    a better one, I'm all ears. (Or technically, eyes.)

    Basically, I have a bunch of classes. For concreteness, one is a
    Matrix class, but that's only one example, so please don't get too hung
    up on it.

    I need to output and input these classes. I'd like a nice, pretty,
    human readable output, something like:
    1 2 3
    4 5 6
    (note spaces and new lines).

    For speed purposes (and yes, I have measured this, and yes, it does
    make a difference), I also want a compressed binary version, which
    would look like this:
    <rows><columns><num>*
    (note: no delimiters, you get all the info from the rows and columns).

    I definitely need to read and write the binary version, but for some
    classes I don't need to read the human readable version.

    So what I have looks like this:

    /// Output in textual format
    std::eek:stream& operator<<(std::eek:stream& os, const Matrix& m);
    /// Output in binary format
    BinaryOStream& operator<<(BinaryOStream& os, const Matrix& m);

    where BinaryOStream is defined like this:
    class BinaryOStream
    {
    public:
    /** The underlying ofstream wrapped by this class. */
    std::eek:fstream m_out;

    public:
    /// Create a BinaryOStream from a given filename.
    BinaryOStream(const std::string& filename);
    ~BinaryOStream(void){}

    //etc
    }

    and its constructor opens m_out in binary mode. It also has a series
    of non-member << operators for different data types (some of which are
    implemented as a template).

    What I don't like about the current solution is that I wind up writing
    what feels like twice as much code as I should have to. Especially if
    I need to read in the format (and Matrix is a bad example for this), it
    seems like for most of my classes, the same input should work for both
    (imagine another class where the outputs are the same except that the
    text has spaces and newlines - I won't cut and paste the code here, but
    you get the idea).

    I kind of feel like BinaryOStream should inherit from ostream, and
    implement the decorator pattern; that way I'd just write stuff for
    ostream, and overload for BinaryOStream if I need to, but I can't quite
    figure out how to make that work. (In particular, I would love to be
    able to output stuff to a 'binary ostringstream' for testing purposes,
    instead of to an actual file.)

    Has anyone done this sort of thing before, and if so, found a clean
    solution?

    Michael
     
    Michael, Jan 5, 2007
    #1
    1. Advertising

  2. Michael

    Ondra Holub Guest

    Michael napsal:
    > I have a solution for this, but it feels wrong. If anyone could offer
    > a better one, I'm all ears. (Or technically, eyes.)
    >
    > Basically, I have a bunch of classes. For concreteness, one is a
    > Matrix class, but that's only one example, so please don't get too hung
    > up on it.
    >
    > I need to output and input these classes. I'd like a nice, pretty,
    > human readable output, something like:
    > 1 2 3
    > 4 5 6
    > (note spaces and new lines).
    >
    > For speed purposes (and yes, I have measured this, and yes, it does
    > make a difference), I also want a compressed binary version, which
    > would look like this:
    > <rows><columns><num>*
    > (note: no delimiters, you get all the info from the rows and columns).
    >
    > I definitely need to read and write the binary version, but for some
    > classes I don't need to read the human readable version.
    >
    > So what I have looks like this:
    >
    > /// Output in textual format
    > std::eek:stream& operator<<(std::eek:stream& os, const Matrix& m);
    > /// Output in binary format
    > BinaryOStream& operator<<(BinaryOStream& os, const Matrix& m);
    >
    > where BinaryOStream is defined like this:
    > class BinaryOStream
    > {
    > public:
    > /** The underlying ofstream wrapped by this class. */
    > std::eek:fstream m_out;
    >
    > public:
    > /// Create a BinaryOStream from a given filename.
    > BinaryOStream(const std::string& filename);
    > ~BinaryOStream(void){}
    >
    > //etc
    > }
    >
    > and its constructor opens m_out in binary mode. It also has a series
    > of non-member << operators for different data types (some of which are
    > implemented as a template).
    >
    > What I don't like about the current solution is that I wind up writing
    > what feels like twice as much code as I should have to. Especially if
    > I need to read in the format (and Matrix is a bad example for this), it
    > seems like for most of my classes, the same input should work for both
    > (imagine another class where the outputs are the same except that the
    > text has spaces and newlines - I won't cut and paste the code here, but
    > you get the idea).
    >
    > I kind of feel like BinaryOStream should inherit from ostream, and
    > implement the decorator pattern; that way I'd just write stuff for
    > ostream, and overload for BinaryOStream if I need to, but I can't quite
    > figure out how to make that work. (In particular, I would love to be
    > able to output stuff to a 'binary ostringstream' for testing purposes,
    > instead of to an actual file.)
    >
    > Has anyone done this sort of thing before, and if so, found a clean
    > solution?
    >
    > Michael


    Hi.

    Stream operator<< is not meant for binary output. It is designed for
    formatted output (no matter of ios::binary - on many systems it has no
    special meaning).

    If you really need binary format, you should use ostream::read and
    ostream::write methods. But it has many issues - you have to care about
    sizes of types, because there is no guarantee, how many bytes exactly
    occupies int, long ot other standard types on different platforms. You
    have to care about endianity too. If you ignore these issues, you will
    produce non-portable code and it will not probably work for example on
    64-bit systems and 32-bit systems.
     
    Ondra Holub, Jan 5, 2007
    #2
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Rasmusson, Lars
    Replies:
    1
    Views:
    782
    popov
    Apr 30, 2004
  2. Replies:
    9
    Views:
    673
    Alex Buell
    Apr 27, 2006
  3. Alexander Korsunsky

    get stream mode flags from an opened stream

    Alexander Korsunsky, Feb 17, 2007, in forum: C++
    Replies:
    1
    Views:
    476
    John Harrison
    Feb 17, 2007
  4. dolphin
    Replies:
    6
    Views:
    595
    Thomas Fritsch
    Mar 18, 2007
  5. Replies:
    8
    Views:
    544
Loading...

Share This Page