Clean binary stream

M

Michael

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
 
O

Ondra Holub

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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top