Topic: basic_fstream for _binary_ files?


Author: Bill Clarke <llib@computer.org>
Date: 1998/02/06
Raw View
David Marshall wrote:
[...]
> Steve Clamage wrote in message <6b9601$8j7@engnews1.Eng.Sun.COM>...
[...use write function...]
>
[...but i want to use my previously defined classes' member functions which
use << and >>...]

the problem is that text formatting and binary output are essentially
different beasts:

"textual" formatting is _formatting_ and so usually includes explicit gaps
(spaces, tabs, newlines) and potentially other _readable_ information.
reading this back in requires parsing the textual information, checking it
for the correct format etc.  so reading and writing textual information are
not easily complementary.

with binary IO, there is no padding, so reading and writing are essentially
opposites.  i would suggest for each class that needs to be written,
include within it a private POD struct which includes all the plain data
that needs to be recorded/loaded (all "non-plain" data elements must also
do this method). then when an instance is to be written (member function
"write"?), fill in the private struct with the plain data and write it to
the stream, and then call non-plain data member's "write" methods as well.

cheers,
/lib
--
/lib: Bill Clarke  CRC for Advanced Computational Systems ANU  Volleyball
http://goblet.anu.edu.au/c9104506  mailto:llib@computer.org  Cricket  mp3
work: +61 2 6279 8192  home: +61 2 6251 4576  DeepPurple  Queen  KLF  H&C
PinkFloyd v1.2a s+d>r TW 1/0/pw Gfm 1? pp Animals 7 11 48% <21jan98>  mud
unix  C++  ML  Java  LaTeX  tcsh  emacs  DrWho  StarTrek  XFiles  Goodies
XPilot  MPI  FEM  Asimov  Bear  Clarke  Jordan  Lackey  Stasheff  Origami
---
[ 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://reality.sgi.com/austern/std-c++/faq.html                  ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1998/02/05
Raw View
Patrik Staehli wrote:
>
> Hi
>
> I couldn't figure out how to create a file-stream which would work with
> _binary_ files instead of text files. The openmode flag 'binary' seems
> only to suppress interpretation of newline etc., if it does anything at
> all.
>
> I even tried playing around with the char_traits class, but the results
> were either compile or linker errors :-(.
>
> Doesn't the STL include binary filestreams or could MS VC++ 5.0 be my
> real problem?
>
> All I want is a filestream which doesn't read/write integers (or
> whatever) in text mode but in binary mode (e.g. 4 bytes for a 32 bit
> integer). Do I really have to code it all by myself?
>
> Any help is appreciated

Look at the sections for unformatted I/O:

Section 27.6.1.3 paragraph 7:
basic_istream& read(char_type* s, streamsize n);

Section 27.6.2.6 paragraph 2:
basic_ostream& write(const char_type* s, streamsize n);
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: clamage@Eng.sun.com (Steve Clamage)
Date: 1998/02/05
Raw View
In article q4e@portal.gmu.edu, "David Marshall" <marshall@avtec.com> writes:
>
>Steve Clamage wrote in message <6b9601$8j7@engnews1.Eng.Sun.COM>...
>>It sounds like you are trying to output binary values with the <<
>>operator. By definition, the << operator converts its operand to a
>>text representation, independent of the mode of the destination stream.
>>
>>Use the "write" function to output binary data to a stream that
>>was opened in binary mode.
>>
>>(It's the same as in C. You don't use printf to output binary data,
>>you use fwrite.)
>
>
>But what if you want to write binary data using the << and >> operators?

Perhaps it would help to review the design strategy of iostreams.
Iostreams have two layers. At the bottom is the transport layer.
It provides the interface between the source or sink and the top
layer. In particular, a filebuf knows about different file types --
at minimum "text files" and "binary files" -- and how to convert data
between the file system representation and the internal program
representation.

The top iostream layer is the formatting layer. It provides the interface
between the user code and the transport layer. It doesn't know or care
about transport details, or whether the source or sink is a text file,
binary file, string, socket, or a programmable machine tool. By design,
the shift operators perform formatting such as text-binary conversion,
inserting pad characters, and so on, sending the converted and formatted
data to the transport layer. By design, the read and write functions pass
through their data unchanged to the transport layer.

This design was not intended to support unformatted I/O using shift
operators. In particular, the shift operators were not designed to
be overridden or replaced. It may be possible to get the effect you
want, but it is probably difficult and may be unreliable. In addition,
it may be confusing within your program if "target << int_value"
sometimes does not involve a text conversion.

I agree it is less pleasant to have to say
 target.write(&val1, sizeof(val1));
 target.write(&val2, sizeof(val2));
instead of
 target << val1 << val2;

You could create manipulators that take values, call the write
function, and return the stream. Then you could write
 target << send(val1) << send(val2);

---
Steve Clamage, stephen.clamage@sun.com




[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Theodore Todorov <todorov@sbghp10.in2p3.fr>
Date: 1998/02/06
Raw View
Patrik Staehli wrote:
> I couldn't figure out how to create a file-stream which would work with
> _binary_ files instead of text files. The openmode flag 'binary' seems
> only to suppress interpretation of newline etc., if it does anything at
> all.
>
.........
>
> All I want is a filestream which doesn't read/write integers (or
> whatever) in text mode but in binary mode (e.g. 4 bytes for a 32 bit
> integer). Do I really have to code it all by myself?
>
> Any help is appreciated

I agree that the support for binary I/O in the standard C++ library
is poor, and I had to create my own binary_streams to be able
to use << and >> for binary I/O. The good news is that it's not
very hard to do it, except for the inevitable problems of portability
of binary representations, I/O size of basic types, byte swapping
on little/big - endian architectures, and all that nice stuff.

The following is my simple implementation that avoids all the
mentioned problems by waiting for them to arise (I only
work on 32 bit IEEE floating point (whatever HP and Sun is) endian
machines so far, but it can easily be extended to deal with all
of them internally without affecting it's clients.
I list just the output stream below for brevity, the binary_ifstream
is very similar.

#include <fstream.h>
#include <string>

class binary_ofstream {

public:
  // Constructors (close to standard)
  binary_ofstream() : my_ofstream() {}
  explicit binary_ofstream(const char* name) : my_ofstream( name) {}

  // Operators for testing stream state
  operator void*() { return my_ofstream;}
  bool operator!() const { return !my_ofstream;}
  bool good() const { return my_ofstream.good();}
  bool eof()  const { return my_ofstream.eof();}
  bool fail() const { return my_ofstream.fail();}
  bool bad() const  { return my_ofstream.bad();}

  void close() { my_ofstream.close();}
  binary_ofstream& flush() { my_ofstream.flush(); return *this;}
  streampos tellp() { return my_ofstream.tellp();}

  // Provide standard write()
  binary_ofstream& write( const char* ptr, int count) {
    my_ofstream.write(ptr, count); return *this;}
  binary_ofstream& write( const unsigned char* ptr, int count) {
    my_ofstream.write(ptr, count); return *this;}

  // Overload write() for simple types
  binary_ofstream& write( char i) {                            // char
    my_ofstream.write((char*) &i, sizeof(char)); return *this;}
  binary_ofstream& write( unsigned char i) {
    my_ofstream.write((char*) &i, sizeof(char)); return *this;}

  binary_ofstream& write( short i) {                           // short
    my_ofstream.write((char*) &i, sizeof(short)); return *this;}
  binary_ofstream& write( unsigned short i) {
    my_ofstream.write((char*) &i, sizeof(short)); return *this;}

  binary_ofstream& write( int i) {                             // int
    my_ofstream.write((char*) &i, sizeof(int)); return *this;}
  binary_ofstream& write( unsigned int i) {
    my_ofstream.write((char*) &i, sizeof(int)); return *this;}

  binary_ofstream& write( float i) {                           // float
    my_ofstream.write((char*) &i, sizeof(float)); return *this;}

  binary_ofstream& write( double i) {                          // double
    my_ofstream.write((char*) &i, sizeof(double)); return *this;}

  binary_ofstream& write( bool i) {                            // bool
    unsigned char tmp = (unsigned char) i;
    return write(tmp);
  }

  binary_ofstream& write( const string& str) {                 // string
    write( static_cast<unsigned short> (str.size()));
    if ( str.size() != 0) my_ofstream.write( str.c_str(), str.size());
    return *this;
  }

private:
  ofstream my_ofstream;
};

template< class T>
inline binary_ofstream& operator<<( binary_ofstream& fout, T ch) {
  return fout.write(ch);}

inline binary_ofstream& operator<<( binary_ofstream& fout, const string&
ch) {
  return fout.write(ch);}

/////////////////////////////////////////////////

One last comment:
My first implementation of this naively inherited publicly from the
standard
ofstream, but as somebody mentioned in this thread that's
not a good idea - ofstream remains accessible for formatted I/O and
it's impossible to protect from mixing the two.

Of course this implementation requires that you do your I/O
explicitly on binary_ofstream etc, but this is not all bad, since
it's the only way to tell from inside a program what kind of I/O
is used.

                    Hope that helps,
                                           Teddy


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1998/02/04
Raw View
Patrik Staehli <DONT_USE@nowhere.ch> writes:

>I couldn't figure out how to create a file-stream which would work with
>_binary_ files instead of text files. The openmode flag 'binary' seems
>only to suppress interpretation of newline etc., if it does anything at
>all. ...

>All I want is a filestream which doesn't read/write integers (or
>whatever) in text mode but in binary mode (e.g. 4 bytes for a 32 bit
>integer). Do I really have to code it all by myself?

It sounds like you are trying to output binary values with the <<
operator. By definition, the << operator converts its operand to a
text representation, independent of the mode of the destination stream.

Use the "write" function to output binary data to a stream that
was opened in binary mode.

(It's the same as in C. You don't use printf to output binary data,
you use fwrite.)

---
Steve Clamage, stephen.clamage@sun.com

--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: "David Marshall" <marshall@avtec.com>
Date: 1998/02/04
Raw View

Steve Clamage wrote in message <6b9601$8j7@engnews1.Eng.Sun.COM>...
>It sounds like you are trying to output binary values with the <<
>operator. By definition, the << operator converts its operand to a
>text representation, independent of the mode of the destination stream.
>
>Use the "write" function to output binary data to a stream that
>was opened in binary mode.
>
>(It's the same as in C. You don't use printf to output binary data,
>you use fwrite.)
>
>---
>Steve Clamage, stephen.clamage@sun.com


But what if you want to write binary data using the << and >> operators?  I
have a need to read/write a platform independent binary stream.  All of the
classes that would be used in this stream have the << and >> operators
already defined for istreams and ostreams, and  I have the conversions for
the basic data types (i.e. local int, double, etc.  to p.i. int, double,
etc. and back).

I think it would be much more convenient to inherit from basic_streambuf
(say my_streambuf) and create a special class that gets/puts basic data
types to/from my_streambuf.  I know that the num_put and num_get templates
are where the data manipulation occurs, but I don't know how to tell
my_streambuf to use different num_put and num_get templates.

Anyone have any ideas?

-David Marshall




[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Patrik Staehli <DONT_USE@nowhere.ch>
Date: 1998/02/03
Raw View
Hi

I couldn't figure out how to create a file-stream which would work with
_binary_ files instead of text files. The openmode flag 'binary' seems
only to suppress interpretation of newline etc., if it does anything at
all.

I even tried playing around with the char_traits class, but the results
were either compile or linker errors :-(.

Doesn't the STL include binary filestreams or could MS VC++ 5.0 be my
real problem?

All I want is a filestream which doesn't read/write integers (or
whatever) in text mode but in binary mode (e.g. 4 bytes for a 32 bit
integer). Do I really have to code it all by myself?

Any help is appreciated
--
Patrik Staehli
p.s(at)bigfoot.com  <-- non-bots will know my address
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]