Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Binary file i/o

117 views
Skip to first unread message

Shyamala Bhat

unread,
Dec 12, 1996, 3:00:00 AM12/12/96
to

Can somebody help me with i/o on binary files using C++ iostreams ?

The following program ( that tries to copy one binary
file into another ) failed with HP C++ on HP-UX :

main()
{
fstream fs1("a.out",ios::in); //a.out is a binary file
fstream fs2("a.out.new",ios::out);

char buffer[1024];

while( !fs1.eof()) //should be set on by last byte in file;does'nt
happen !
{
fs1>>buffer;
fs2<< buffer;
}
}

How do I set the i/o mode to binary while opening a stream ?

Regards,
Shyamala

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


Mike Monagle

unread,
Dec 12, 1996, 3:00:00 AM12/12/96
to

Use:

fstream fs1("a.out", ios::in | ios::binary);
fstream fs2("a.out.new", ios::out | ios::binary);

You can also use an ifstream for fs1 and an ofstream for fs2 if you like.

Mike

In article <58p57q$p...@netlab.cs.rpi.edu>, Shyamala says...

Dietmar Kuehl

unread,
Dec 13, 1996, 3:00:00 AM12/13/96
to

Hi,
Shyamala Bhat (shya...@india.hp.com) wrote:
: Can somebody help me with i/o on binary files using C++ iostreams ?

Apparently, the first help is to tell you that IOStreams are not
intended to do binary IO at all. They have some rudimentary support (by
means of the 'read()' and 'write()' members) but not sufficient to do
real binary IO (IMO).

: The following program ( that tries to copy one binary


: file into another ) failed with HP C++ on HP-UX :

: main()

BTW: The implicit int rule will not be part of ISO C++: You need to
explicitly declare the return type of all functions, including
'main()'.

: {
: fstream fs1("a.out",ios::in); //a.out is a binary file


: fstream fs2("a.out.new",ios::out);

Well, if "a.out" is a binary file, you should open it as such (and
probably "a.out.new", too):

ifstream fs1("a.out",ios::in | ios::binary);
ofstream fs2("a.out.new",ios::out | ios::binary);

Although 'ios::binary' is probably not necessary on the system you are
using, it may be necessary on some other systems: On systems like
MS-DOS, the line termination character '\n' is replaced by a sequence
of two characters when writing in text mode while this replacement is
omitted when writing in binary mode. However, the 'ios::binary' flag
does *NOT* indicate that IO using 'operator<<()' and 'operator>>()' is
done in binary: These will still do formatted IO. The only difference
is that a different set of flags is passed to the OS level calls to
open a file.

Also note, that I have replaced 'fstream' by 'ifstream' and
'ofstream': You want to only read from 'fs1' and only write to 'fs2'.
This is what the open mode flags you passed them indicate. I think the
approach of using 'ifstream' and 'ofstream' is less error prone. For
some time, there was the additional argument that 'fstream' will not be
part of the standard C++ library but this change was undone recently.

: char buffer[1024];

: while( !fs1.eof()) //should be set on by last byte in file;does'nt
: happen !

'fs1.eof()' will be set when the attempt to read a byte failed. It will
not be set if the last attempt to read from the file was successful
with the remaining bytes! Thus, you pass through the loop one time too
often. Assuming that non-binary IO is to be done, e.g. reading integer
into an 'int' called 'buffer' the loop has to read something like
this:

for (fs1 >> buffer; !fs1.eof(); fs1 >> buffer)
fs2 << buffer;

However, for binary data this is basically useless: In binary files you
may have sequences of alphanumeric data (the read stops after
successfully reading a word) which exceeds 1024 bytes (e.g. the symbol
table on some systems). Thus, you would have to make the buffer size
basically the same as the file size to be safe. Also, by default,
leading whitespace is ignored by all built-in extractors (i.e. the
'operator>>()' taking an 'istream' as first argument). This has to be
turned off before you can use an extractor for binary IO. This can be
done by clearing the 'ios::skipws' flag:

fs1 >> noskipws; // not yet supported by all libraries
fs1.unsetf(ios::skipws);

After this is done, I think that you should be able copy a binary file
with the following statement:

fs2 << fs1.rdbuf();

You can copy text files with this statement but I'm not sure about
binary files. For binary files, you might use the member functions
'read()' and 'write()' of 'istream' and 'ostream', respectively. You
may also want to avoid using 'istream' and 'ostream' at all and use the
corresponding 'streambuf', e.g. 'filebuf', instead: On 'streambuf'
level you operate on sequences of bytes.

For a "nicer" interface to 'streambuf's giving a look-and-feel of
IOStreams just for binary IO, you might want to have a look at
<ftp://ftp.informatik.uni-konstanz.de/pub/algo/personal/kuehl/binio.tar.gz>.
This file defines 'operator<<()' and 'operator>>()' for binary IO
working on 'obstream' and 'ibstream' (not the 'b' in the name) which
are similar to 'ostream' and 'istream' but just for binary IO writing
data in SUN's XDR format (there are, unfortunately, some problems with
the current implementation, at least on DEC stations, which I haven't
found the time to resolve).
--
<mailto:dietma...@uni-konstanz.de>
<http://www.informatik.uni-konstanz.de/~kuehl/>
I am a realistic optimist - that's why I appear to be slightly pessimistic

James Albert Kanze

unread,
Dec 13, 1996, 3:00:00 AM12/13/96
to

Shyamala Bhat <shya...@india.hp.com> writes:

|> Can somebody help me with i/o on binary files using C++ iostreams ?
|>

|> The following program ( that tries to copy one binary
|> file into another ) failed with HP C++ on HP-UX :
|>
|> main()

|> {


|> fstream fs1("a.out",ios::in); //a.out is a binary file
|> fstream fs2("a.out.new",ios::out);
|>

|> char buffer[1024];
|>
|> while( !fs1.eof()) //should be set on by last byte in file;does'nt
|> happen !

|> {
|> fs1>>buffer;
|> fs2<< buffer;
|> }
|> }
|>
|> How do I set the i/o mode to binary while opening a stream ?

First, you don't say how it failed.

To set the mode to binary, you should or in ios::binary in the mode.
According to the draft standard, of course. In fact, the version of HP
C++ I have access to doesn't support this yet.

At any rate, this is *not* the reason for failure, at least under
HP-UX. Under Unix, the ios::binary bit is a no-op anyway; there is no
difference between binary and non-binary files. (IMHO: you should set
it anyway, since it is required by the standard. The fact that the
program just happens work is not an excuse.)

Note, however, that the extraction and insertion operators (>> and <<)
do formatted input. This is independant of the mode of the file.
Binary (non-formatted) io can be done in several ways:

1. The most obvious is to use the non-formatting routines istream::read
and ostream::write. I'm not to sure about this, however, since
according to the draft I have, read will set ios::failbit if it fails to
extract all of the characters requested. In addition, I find it awkward
that the number of characters actually extracted must be determined by a
separate function, e.g.: istream::gcount.

2. You can, of course, bypass the iostream completely, and just use the
streambuf. Although I've rarely seen this, it is, IMHO, very logical.
The iostream.h file defines two distinct abstractions: formatting
(classes ios and derivatives) and sinking/sourcing bytes (streambuf).
Since all you want is to sink and source bytes, why use the other
abstraction.

In this case, you will create filebuf's instead of istream and ostream.
(Although some implementations of filebuf have a constructor which takes
the filename and the mode, this is not in the draft, and it also fails
to provide an effective means of detecting errors. I would recommend
using the default constructor, then the open function.)

The functions you are interested in are sgetn and sputn; when sgetn says
you read 0 characters, you are finished.

3. Finally, the easiest way for this one special case (copying): just
write:

fs2 << fs1.rdbuf() ;

This is a general way of dumping all of the characters from one stream
into another stream. (In a more typical use, fs1 would be an ostrstream
built up in some other function.) Note that it requires no external
loop, nor any external buffer.


One final point: the results of ios::eof() are not really well defined.
(It is not defined whether the function is predictive, i.e.: what the
function will return if the last read succeeded, but the next will
fail.) Use rather ios::fail(), which will only return true after the
read actually failed. (When doing formatted input, it is then necessary
to test whether the failure is due to a formatting error, or to end of
file.)

--
James Kanze home: ka...@gabi-soft.fr +33 (0)3 88 14 49 00
office: ka...@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 8 rue des Francs Bourgeois, F-67000 Strasbourg, France
-- Conseils en informatique industrielle --

James Albert Kanze

unread,
Dec 16, 1996, 3:00:00 AM12/16/96
to

ku...@kalkofen.informatik.uni-konstanz.de (Dietmar Kuehl) writes:

|> Also, by default,
|> leading whitespace is ignored by all built-in extractors (i.e. the
|> 'operator>>()' taking an 'istream' as first argument). This has to be
|> turned off before you can use an extractor for binary IO. This can be
|> done by clearing the 'ios::skipws' flag:
|>
|> fs1 >> noskipws; // not yet supported by all libraries
|> fs1.unsetf(ios::skipws);
|>
|> After this is done, I think that you should be able copy a binary file
|> with the following statement:
|>
|> fs2 << fs1.rdbuf();

Actually, if you look, you'll notice that the above doesn't ever use
operator>>, so you don't have to turn off skipws (although Dietmar's
comments are true in general).

|> You can copy text files with this statement but I'm not sure about
|> binary files.

I'm fairly sure it works for binary files. (I know it works on my
implementations, and I'm fairly sure that it is required to work by the
standard, provided the files have been opened using ios::binary.)

|> For binary files, you might use the member functions
|> 'read()' and 'write()' of 'istream' and 'ostream', respectively. You
|> may also want to avoid using 'istream' and 'ostream' at all and use the
|> corresponding 'streambuf', e.g. 'filebuf', instead: On 'streambuf'
|> level you operate on sequences of bytes.

Two comments:

1. IMHO, if you are really doing pure binary IO, then just using
streambuf is the correct solution, and

2. IMHO, if you are really doing pure binary IO, you are probably not
doing the right thing. Binary data on a file are inherently
non-portable, including from one release of the compiler to the next.

There are exceptions, of course, of which a direct file copy is one.
Most of the time, however, "binary" io is only used to physically sink
and source something formatted. (Not necessarily with an ASCII based
format, of course. Compressed data a la gzip, for example, also have an
internal format, so that you can read and write on machines with
different endian-ness.)

|> For a "nicer" interface to 'streambuf's giving a look-and-feel of
|> IOStreams just for binary IO, you might want to have a look at
|> <ftp://ftp.informatik.uni-konstanz.de/pub/algo/personal/kuehl/binio.tar.gz>.
|> This file defines 'operator<<()' and 'operator>>()' for binary IO
|> working on 'obstream' and 'ibstream' (not the 'b' in the name) which
|> are similar to 'ostream' and 'istream' but just for binary IO writing
|> data in SUN's XDR format (there are, unfortunately, some problems with
|> the current implementation, at least on DEC stations, which I haven't
|> found the time to resolve).

This sounds like a nice solution.

Keith Davies

unread,
Dec 19, 1996, 3:00:00 AM12/19/96
to

On 16 Dec 1996 15:48:10 -0500, James Albert Kanze
<james-alb...@vx.cit.alcatel.fr> wrote:

> ku...@kalkofen.informatik.uni-konstanz.de (Dietmar Kuehl) writes:
>
> There are exceptions, of course, of which a direct file copy is one.
> Most of the time, however, "binary" io is only used to physically sink
> and source something formatted. (Not necessarily with an ASCII based
> format, of course. Compressed data a la gzip, for example, also have an
> internal format, so that you can read and write on machines with
> different endian-ness.)
>
> |> For a "nicer" interface to 'streambuf's giving a look-and-feel of
> |> IOStreams just for binary IO, you might want to have a look at
> |> <ftp://ftp.informatik.uni-konstanz.de/pub/algo/personal/kuehl/binio.tar.gz>.
> |> This file defines 'operator<<()' and 'operator>>()' for binary IO
> |> working on 'obstream' and 'ibstream' (not the 'b' in the name) which
> |> are similar to 'ostream' and 'istream' but just for binary IO writing
> |> data in SUN's XDR format (there are, unfortunately, some problems with
> |> the current implementation, at least on DEC stations, which I haven't
> |> found the time to resolve).
>
> This sounds like a nice solution.

I have also implemented streams that operate at the byte level (bit
level, if desired). The first cut of the library will be available at
www.coastnet.com/~entropy sometime later this afternoon.

Keith
--
Keith Davies - DarkBlade Software | GCS3.0 d-(+) s+:+ a22 C++ UL++(++++) P+
kda...@pinc.com | L+ E W+(+++) N++ K w++@ !O M-- V-(--)
voice: (604) 385-8536 | PS+++ PE+(-) Y PGP-(--) t 5 X R+ tv---
modem: (604) 386-8536 | b+++ DI++ D+ G e+ h--- r+++ y++++
"Memory is like an orgasm. It's a lot better if you don't have to fake it."
-Seymore Cray, on virtual memory

0 new messages