By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,750 Members | 1,187 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,750 IT Pros & Developers. It's quick & easy.

Grrr... C++ file I/O

P: n/a
Damn.. FILE *fp was just sooo much easier than C++ file i/o...
I just don't get it.. really!

filebuf, istream, ostream, ifstream, ofstream, iosteam...
what the f&(){( do I use to do binary file i/o read and write.
I need to be able to read and write, seek and tell
which class do I use?????

frustrated..

Jun 8 '07 #1
Share this Question
Share on Google+
30 Replies


P: n/a
"SpreadTooThin" writes:
Damn.. FILE *fp was just sooo much easier than C++ file i/o...
I just don't get it.. really!

filebuf, istream, ostream, ifstream, ofstream, iosteam...
what the f&(){( do I use to do binary file i/o read and write.
I need to be able to read and write, seek and tell
which class do I use?????
Use ios::binary as a parameter the file open.
Use ifstream, tellg, seekg and read to read.
Use ofstream, tellp, seekp, and write to write.

Salt judiciously with std:: until your head swims.
Jun 8 '07 #2

P: n/a
SpreadTooThin <bj********@gmail.comwrites:
>Damn.. FILE *fp was just sooo much easier than C++ file i/o...
I just don't get it.. really!
http://www-h.eng.cam.ac.uk/help/tpl/...es/C++/io.html
*might* help.
Jun 8 '07 #3

P: n/a
Hi,

Simple example

#include <fstream>
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;

int main( int ArgC, char *ArgV[] )
{
//----------------Input example
// bin just to make sure it works the same on ms-windows and unix flavors
(unix'es are always bin)
ifstream Input( "Filename.dat", ios_base::binary );
if( !Input.is_open() )
{
cerr << __LINE__ << "see an error" << endl;
throw "Error";
}
string Line;
while( getline( Input, Line ) )
{
cout << "Read <" << Line << ">" << endl;
}

//-------------------Output example
ofstream Output( "Filenameout.dat", ios_base::binary );
if( !Output.is_open() )
{
cerr << __LINE__ << "see an error" << endl;
throw "Error";
}
// Right left alligned space right padded long as string
long Number = 10;
// The following writes text
Output << setiosflags( ios_base::left ) << resetiosflags(
ios_base::right ) << setw( 20 ) << setfill( ' ' ) << Number << endl;

// This wil write 4 bytes on most 32 bit machines
// Write arbitrary data for instance long
Output.write( reinterpret_cast<char*>( &Number ), sizeof( Number ) ); //
Opposite is Input.read
}

Regards, Ron AF Greve

http://www.InformationSuperHighway.eu

"SpreadTooThin" <bj********@gmail.comwrote in message
news:11**********************@i13g2000prf.googlegr oups.com...
Damn.. FILE *fp was just sooo much easier than C++ file i/o...
I just don't get it.. really!

filebuf, istream, ostream, ifstream, ofstream, iosteam...
what the f&(){( do I use to do binary file i/o read and write.
I need to be able to read and write, seek and tell
which class do I use?????

frustrated..

Jun 8 '07 #4

P: n/a
On Jun 8, 3:00 pm, "osmium" <r124c4u...@comcast.netwrote:
"SpreadTooThin" writes:
Damn.. FILE *fp was just sooo much easier than C++ file i/o...
I just don't get it.. really!
filebuf, istream, ostream, ifstream, ofstream, iosteam...
what the f&(){( do I use to do binary file i/o read and write.
I need to be able to read and write, seek and tell
which class do I use?????

Use ios::binary as a parameter the file open.
Use ifstream, tellg, seekg and read to read.
Use ofstream, tellp, seekp, and write to write.

Salt judiciously with std:: until your head swims.
Am I correct the tellg resets the stream to the begining of the file?
Jun 8 '07 #5

P: n/a
On Jun 8, 3:00 pm, "osmium" <r124c4u...@comcast.netwrote:
"SpreadTooThin" writes:
Damn.. FILE *fp was just sooo much easier than C++ file i/o...
I just don't get it.. really!
filebuf, istream, ostream, ifstream, ofstream, iosteam...
what the f&(){( do I use to do binary file i/o read and write.
I need to be able to read and write, seek and tell
which class do I use?????

Use ios::binary as a parameter the file open.
Use ifstream, tellg, seekg and read to read.
Use ofstream, tellp, seekp, and write to write.

Salt judiciously with std:: until your head swims.
The header files <iostream>, <fstreametc..
I mean what is iostream for?
why not just fstream or ifstream for ifstream and ofstream for
ofstream?

Jun 8 '07 #6

P: n/a
"SpreadTooThin" writes:
Am I correct the tellg resets the stream to the begining of the file?
No. I forgot to mention, g stands for get and p stand for put; there are
two pointers into the file. seekg(0) and seekp(0) will get you to the
beginning of the file, may be syntax errors, I am writing from memory.
Jun 8 '07 #7

P: n/a
On 2007-06-08 23:55, SpreadTooThin wrote:
On Jun 8, 3:00 pm, "osmium" <r124c4u...@comcast.netwrote:
>"SpreadTooThin" writes:
Damn.. FILE *fp was just sooo much easier than C++ file i/o...
I just don't get it.. really!
filebuf, istream, ostream, ifstream, ofstream, iosteam...
what the f&(){( do I use to do binary file i/o read and write.
I need to be able to read and write, seek and tell
which class do I use?????

Use ios::binary as a parameter the file open.
Use ifstream, tellg, seekg and read to read.
Use ofstream, tellp, seekp, and write to write.

Salt judiciously with std:: until your head swims.

Am I correct the tellg resets the stream to the begining of the file?
No, tellg() tells you where you are, if you want to go somewhere use
seekg(). For more documentation about streams have a look at
www.cplusplus.com

--
Erik Wikström
Jun 8 '07 #8

P: n/a
On Jun 8, 4:48 pm, "osmium" <r124c4u...@comcast.netwrote:
"SpreadTooThin" writes:
Am I correct the tellg resets the stream to the begining of the file?

No. I forgot to mention, g stands for get and p stand for put; there are
two pointers into the file. seekg(0) and seekp(0) will get you to the
beginning of the file, may be syntax errors, I am writing from memory.
But in no circumstance will tell reposition the file pointer?

Jun 8 '07 #9

P: n/a
On Jun 9, 12:48 am, "osmium" <r124c4u...@comcast.netwrote:
"SpreadTooThin" writes:
Am I correct the tellg resets the stream to the begining of the file?
No. I forgot to mention, g stands for get and p stand for put; there are
two pointers into the file. seekg(0) and seekp(0) will get you to the
beginning of the file, may be syntax errors, I am writing from memory.
No there aren't. In general, at the [io]stream level, it is
unspecified whether a bi-directional stream maintains two
pointers, or one. The interface is designed to support two,
since some streams (e.g. stringstream) do support two, but
changing the read position (seekg()) on a fstream will also
change the write position.

Be aware, too, that all of the restrictions as to what
positionning is legal on a FILE* also apply to [io]stream. In
practice, on a text stream, you can only seek to the beginning,
or to a place where you've been before, and whose position you
obtained using tell[gp]. (And of course tell[gp] never changes
the position in the file.)

--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 8 '07 #10

P: n/a
SpreadTooThin wrote:
Damn.. FILE *fp was just sooo much easier than C++ file i/o...
Then why don't you use it? It's not like it doesn't work in C++.
Jun 9 '07 #11

P: n/a
On Sat, 09 Jun 2007 11:17:30 +0300, Juha Nieminen wrote:
>SpreadTooThin wrote:
>Damn.. FILE *fp was just sooo much easier than C++ file i/o...

Then why don't you use it? It's not like it doesn't work in C++.
I always prefer stdio to iostream if I have the choice. It's also not
difficult to wrap FILE* and the functions into a safer class.
--
Roland Pibinger
"The best software is simple, elegant, and full of drama" - Grady Booch
Jun 9 '07 #12

P: n/a
On Jun 9, 2:17 am, Juha Nieminen <nos...@thanks.invalidwrote:
SpreadTooThin wrote:
Damn.. FILE *fp was just sooo much easier than C++ file i/o...

Then why don't you use it? It's not like it doesn't work in C++.
I guess part of it is keeping up with the times (even if C++ is not
a spring chicken in terms of technological age.) and being able to
look at other peoples code and understand it. The same question may
be why C++ if you liked C. But yes I understand where you are comming
from.

B.

Jun 9 '07 #13

P: n/a
Roland Pibinger wrote:
I always prefer stdio to iostream if I have the choice.
The problem with stdio is that it's not abstract enough.
Example:

typedef int ValueType;
....
ValueType i = 4;
printf("%i\n", i); // this times 100 in a large program.

Later you notice that int is actually not enough, and you are
compiling for a 64-bit system, so you change:

typedef long ValueType;

and all your printfs break.

Ok, you could use a kludge and say:

typedef int ValueType;
#define VALUE_TYPE_FORMAT_STR "%i"
....
ValueType i = 4;
printf(VALUE_TYPE_FORMAT_STR"\n", i);

But then in the future you notice that actually int nor even long
is enough, so you replace the typedef with

class ValueType { ... }; // eg. a 256-bit integer

and all your printfs break.
Jun 9 '07 #14

P: n/a
On Jun 9, 10:17 am, Juha Nieminen <nos...@thanks.invalidwrote:
SpreadTooThin wrote:
Damn.. FILE *fp was just sooo much easier than C++ file i/o...
Then why don't you use it? It's not like it doesn't work in
C++.
Why would it work in C++? It didn't work in C, at least for
formatted IO.

--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 9 '07 #15

P: n/a
James Kanze wrote:
On Jun 9, 10:17 am, Juha Nieminen <nos...@thanks.invalidwrote:
>SpreadTooThin wrote:
>>Damn.. FILE *fp was just sooo much easier than C++ file i/o...
> Then why don't you use it? It's not like it doesn't work in
C++.

Why would it work in C++? It didn't work in C, at least for
formatted IO.
Because in C++ you can wrap the FILE* in a class. Maybe even overload
an operator to automatically format the primitive types for you before
writing. And then clients could also overload that operator to format
their own types. Maybe operator<< would be a good choice.

--
Alan Johnson
Jun 10 '07 #16

P: n/a
On Sat, 09 Jun 2007 20:37:41 +0300, Juha Nieminen wrote:
The problem with stdio is that it's not abstract enough.
Example:
You example indicates that stdio may not be type-safe enough (not that
it's not abstract enough).
>typedef int ValueType;
...
ValueType i = 4;
printf("%i\n", i); // this times 100 in a large program.

Later you notice that int is actually not enough, and you are
compiling for a 64-bit system, so you change:

typedef long ValueType;

and all your printfs break.

Ok, you could use a kludge and say:

typedef int ValueType;
#define VALUE_TYPE_FORMAT_STR "%i"
...
ValueType i = 4;
printf(VALUE_TYPE_FORMAT_STR"\n", i);
Your integer value has a specific meaning in the current context which
could be expressed by a type-safe wrapper function, e.g.

inline
int printAmount (int i) {
return printf("%i\n", i);
}
But then in the future you notice that actually int nor even long
is enough, so you replace the typedef with

class ValueType { ... }; // eg. a 256-bit integer

and all your printfs break.
In theory you can write an operator<< for ValueType, in practice you
don't know a general purpose format to write one and need funtions for
different formatted outputs anyway.
--
Roland Pibinger
"The best software is simple, elegant, and full of drama" - Grady Booch
Jun 10 '07 #17

P: n/a
Roland Pibinger wrote:
Your integer value has a specific meaning in the current context which
could be expressed by a type-safe wrapper function, e.g.

inline
int printAmount (int i) {
return printf("%i\n", i);
}
That only works if you want to print the value to stdout with that
exact format. What if you want to print it with another format (and
possibly alongside other values and text) and for example to a
char array instead of stdout?
Jun 10 '07 #18

P: n/a
On Sun, 10 Jun 2007 14:01:46 +0300, Juha Nieminen wrote:
>Roland Pibinger wrote:
>Your integer value has a specific meaning in the current context which
could be expressed by a type-safe wrapper function, e.g.

inline
int printAmount (int i) {
return printf("%i\n", i);
}

That only works if you want to print the value to stdout with that
exact format. What if you want to print it with another format (and
possibly alongside other values and text) and for example to a
char array instead of stdout?
It depends on the number of print requirements in your application.
Unless you need hundreds of different formats small wrapper functions
are appropriate. The 'backend' functions (printf, fprintf, snprintf)
are ready for use and wrappers are implemented quickly. At least I
prefer functions like printDateISO() etc.
--
Roland Pibinger
"The best software is simple, elegant, and full of drama" - Grady Booch
Jun 10 '07 #19

P: n/a
On Sat, 09 Jun 2007 08:36:22 +0000, Roland Pibinger wrote:
On Sat, 09 Jun 2007 11:17:30 +0300, Juha Nieminen wrote:
>>SpreadTooThin wrote:
>>Damn.. FILE *fp was just sooo much easier than C++ file i/o...

Then why don't you use it? It's not like it doesn't work in C++.

I always prefer stdio to iostream if I have the choice. It's also not
difficult to wrap FILE* and the functions into a safer class.
I believe that has been done before... for one such implementation see
the standard fstream classes ;-)

--
Lionel B
Jun 11 '07 #20

P: n/a
On Jun 9, 10:47 am, SpreadTooThin <bjobrie...@gmail.comwrote:
The header files <iostream>, <fstreametc..
I mean what is iostream for?
It declares cin, cout, cerr, clog. Similar to how
stdio.h declares stdin, stdout, stderr.
why not just fstream or ifstream for ifstream and ofstream for
ofstream?
Huh? <fstreamdefines both ifstream and ofstream.
<istreamincludes other operations that apply to
all input streams (not just file ones).

Jun 12 '07 #21

P: n/a
On Jun 11, 10:03 pm, Old Wolf <oldw...@inspire.net.nzwrote:
On Jun 9, 10:47 am, SpreadTooThin <bjobrie...@gmail.comwrote:
The header files <iostream>, <fstreametc..
I mean what is iostream for?

It declares cin, cout, cerr, clog. Similar to how
stdio.h declares stdin, stdout, stderr.
why not just fstream or ifstream for ifstream and ofstream for
ofstream?

Huh? <fstreamdefines both ifstream and ofstream.
<istreamincludes other operations that apply to
all input streams (not just file ones).
so if I had a stream of data on a socket I could derive
a class from istream?

Jun 12 '07 #22

P: n/a
On Jun 8, 3:00 pm, "osmium" <r124c4u...@comcast.netwrote:
"SpreadTooThin" writes:
Damn.. FILE *fp was just sooo much easier than C++ file i/o...
I just don't get it.. really!
filebuf, istream, ostream, ifstream, ofstream, iosteam...
what the f&(){( do I use to do binary file i/o read and write.
I need to be able to read and write, seek and tell
which class do I use?????

Use ios::binary as a parameter the file open.
Use ifstream, tellg, seekg and read to read.
Use ofstream, tellp, seekp, and write to write.

Salt judiciously with std:: until your head swims.
if you are using fstream then do you use tellg or tellp?
Jun 12 '07 #23

P: n/a
SpreadTooThin <bj********@gmail.comwrote:
On Jun 8, 3:00 pm, "osmium" <r124c4u...@comcast.netwrote:
>Use ios::binary as a parameter the file open.
Use ifstream, tellg, seekg and read to read.
Use ofstream, tellp, seekp, and write to write.

Salt judiciously with std:: until your head swims.

if you are using fstream then do you use tellg or tellp?
tellg() tells you where the "get" pointer will be reading from.
tellp() tells you where the "put" pointer will write to.

On some implementations, the two pointers may be synchronized.

--
Marcus Kwok
Replace 'invalid' with 'net' to reply
Jun 12 '07 #24

P: n/a
On Jun 13, 3:09 am, SpreadTooThin <bjobrie...@gmail.comwrote:
so if I had a stream of data on a socket I could derive
a class from istream?
I suppose you could (although I haven't tried it).

Note that the streams interface is designed to be
used in a blocking manner, so if you were doing a
non-trivial socket application then this method
might not be to your taste.
Jun 12 '07 #25

P: n/a
On 2007-06-12, Old Wolf <ol*****@inspire.net.nzwrote:
On Jun 13, 3:09 am, SpreadTooThin <bjobrie...@gmail.comwrote:
>so if I had a stream of data on a socket I could derive
a class from istream?

I suppose you could (although I haven't tried it).

Note that the streams interface is designed to be
used in a blocking manner, so if you were doing a
non-trivial socket application then this method
might not be to your taste.
Note that basic_istream has precious few virtual functions so deriving
from the istream gives you poor opportunity for influencing the way
the stream interface behaves. If you look at how *stringstream and
*fstream classes work, they generally have very little added
functionality. They usually just have an explicit constructor to set
up a particular type of streambuf and perhaps a few other methods
which are particular to the type of streambuf involved.

If you want to change where you are reading and writing from in
istream/ostream calls (e.g. istream/ostream on top of a socket) then
you are probably better of deriving a custom class derived from
basic_streambuf. Then you only have to worry about where to put/get
the raw bytes from and you can construct istream/ostream interfaces
around your streambuf to provide all the formatting capabilities. Any
functionality which uses the [io]stream classes will be able to run
with the new streambuf without modification.

If you want the change the way in which various types are written out
then you may find that you can achieve what you want by implementing a
local::facet. You might, for instance, decide that integers should
really be serialised in a custom base64 style encoding. You could
then implement num_get and num_out facets. You can use this with the
standard iostreams by creating a new locale (std::locale has methods
for retrieving a copy of either the global locale or the "classic"
one), patching in your custom facets and imbueing (calling
ios_base::imbue) the stream with your custom locale.

The streams library is very flexible, but deriving from istream
directly probably won't give you the flexibility that you are looking
for.
Jun 13 '07 #26

P: n/a
On Jun 13, 9:33 am, Charles Bailey <usenetspa...@hashpling.orgwrote:
On 2007-06-12, Old Wolf <oldw...@inspire.net.nzwrote:
On Jun 13, 3:09 am, SpreadTooThin <bjobrie...@gmail.comwrote:
so if I had a stream of data on a socket I could derive
a class from istream?
I suppose you could (although I haven't tried it).
As mentionned below, the main class you have to work with here
is streambuf; you derive from [io]stream only to automatically
create the correct streambuf.

And I can't remember any real application where I didn't do
this at least once.
Note that the streams interface is designed to be
used in a blocking manner, so if you were doing a
non-trivial socket application then this method
might not be to your taste.
Unless you're working in a multithreaded environment.

The real problem is the limited possibilties of error reporting.
Note that basic_istream has precious few virtual functions so deriving
from the istream gives you poor opportunity for influencing the way
the stream interface behaves. If you look at how *stringstream and
*fstream classes work, they generally have very little added
functionality. They usually just have an explicit constructor to set
up a particular type of streambuf and perhaps a few other methods
which are particular to the type of streambuf involved.
If you want to change where you are reading and writing from in
istream/ostream calls (e.g. istream/ostream on top of a socket) then
you are probably better of deriving a custom class derived from
basic_streambuf. Then you only have to worry about where to put/get
the raw bytes from and you can construct istream/ostream interfaces
around your streambuf to provide all the formatting capabilities. Any
functionality which uses the [io]stream classes will be able to run
with the new streambuf without modification.
In fact, this is the only way to change where you are reading
and writing from. The class derived from [io]stream is really
just for convenience, so that the user doesn't have to
explicitly declare his own streambuf object before declaring the
[io]stream object.
If you want the change the way in which various types are written out
then you may find that you can achieve what you want by implementing a
local::facet. You might, for instance, decide that integers should
really be serialised in a custom base64 style encoding. You could
then implement num_get and num_out facets. You can use this with the
standard iostreams by creating a new locale (std::locale has methods
for retrieving a copy of either the global locale or the "classic"
one), patching in your custom facets and imbueing (calling
ios_base::imbue) the stream with your custom locale.
That sounds a lot like abuse to me, and is likely to cause
trouble, since more complex objects like std::complex count on a
particular format. (In fact, std::complex doesn't even work
correctly in most European locales. That, I believe, is
considered an error, but I don't think the committee would
recognize it an error if e.g. it didn't work with
num_get/num_put facets which did binary output.)
The streams library is very flexible, but deriving from
istream directly probably won't give you the flexibility that
you are looking for.
No. It's more for convenience.

Deriving from ios is often done, however, for things like binary
streams, in order to get the standard error handling.

--
James Kanze (GABI Software, from CAI) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 13 '07 #27

P: n/a
On Jun 13, 10:18 am, James Kanze <james.ka...@gmail.comwrote:
On Jun 13, 9:33 am, Charles Bailey <usenetspa...@hashpling.orgwrote:
On 2007-06-12, Old Wolf <oldw...@inspire.net.nzwrote:
On Jun 13, 3:09 am, SpreadTooThin <bjobrie...@gmail.comwrote:
>so if I had a stream of data on a socket I could derive
>a class from istream?
I suppose you could (although I haven't tried it).

As mentionned below, the main class you have to work with here
is streambuf; you derive from [io]stream only to automatically
create the correct streambuf.

And I can't remember any real application where I didn't do
this at least once.
Note that the streams interface is designed to be
used in a blocking manner, so if you were doing a
non-trivial socket application then this method
might not be to your taste.

Unless you're working in a multithreaded environment.

The real problem is the limited possibilties of error reporting.
Note that basic_istream has precious few virtual functions so deriving
from the istream gives you poor opportunity for influencing the way
the stream interface behaves. If you look at how *stringstream and
*fstream classes work, they generally have very little added
functionality. They usually just have an explicit constructor to set
up a particular type of streambuf and perhaps a few other methods
which are particular to the type of streambuf involved.
If you want to change where you are reading and writing from in
istream/ostream calls (e.g. istream/ostream on top of a socket) then
you are probably better of deriving a custom class derived from
basic_streambuf. Then you only have to worry about where to put/get
the raw bytes from and you can construct istream/ostream interfaces
around your streambuf to provide all the formatting capabilities. Any
functionality which uses the [io]stream classes will be able to run
with the new streambuf without modification.

In fact, this is the only way to change where you are reading
and writing from. The class derived from [io]stream is really
just for convenience, so that the user doesn't have to
explicitly declare his own streambuf object before declaring the
[io]stream object.
If you want the change the way in which various types are written out
then you may find that you can achieve what you want by implementing a
local::facet. You might, for instance, decide that integers should
really be serialised in a custom base64 style encoding. You could
then implement num_get and num_out facets. You can use this with the
standard iostreams by creating a new locale (std::locale has methods
for retrieving a copy of either the global locale or the "classic"
one), patching in your custom facets and imbueing (calling
ios_base::imbue) the stream with your custom locale.

That sounds a lot like abuse to me, and is likely to cause
trouble, since more complex objects like std::complex count on a
particular format. (In fact, std::complex doesn't even work
correctly in most European locales. That, I believe, is
considered an error, but I don't think the committee would
recognize it an error if e.g. it didn't work with
num_get/num_put facets which did binary output.)
The streams library is very flexible, but deriving from
istream directly probably won't give you the flexibility that
you are looking for.

No. It's more for convenience.

Deriving from ios is often done, however, for things like binary
streams, in order to get the standard error handling.

--
James Kanze (GABI Software, from CAI) email:james.ka...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
there are two C++ important things I never found in a C++ mainstream
book:
- a detailed description/tutorial/pitfall on implementing custom
streams;
- a detailed description/tutorial/pitfall on implementing custom
iterators;

why? :(

Jun 13 '07 #28

P: n/a
On 2007-06-13, James Kanze <ja*********@gmail.comwrote:
On Jun 13, 9:33 am, Charles Bailey <usenetspa...@hashpling.orgwrote:
>If you want the change the way in which various types are written out
then you may find that you can achieve what you want by implementing a
local::facet. You might, for instance, decide that integers should
really be serialised in a custom base64 style encoding. You could
then implement num_get and num_out facets. You can use this with the
standard iostreams by creating a new locale (std::locale has methods
for retrieving a copy of either the global locale or the "classic"
one), patching in your custom facets and imbueing (calling
ios_base::imbue) the stream with your custom locale.

That sounds a lot like abuse to me, and is likely to cause
trouble, since more complex objects like std::complex count on a
particular format. (In fact, std::complex doesn't even work
correctly in most European locales. That, I believe, is
considered an error, but I don't think the committee would
recognize it an error if e.g. it didn't work with
num_get/num_put facets which did binary output.)
My example was bad. The usual facets are fairly flexible but in
theory, if you have an obscure locale with an interesting way of
writing numbers that you need to support (or have invented ;) ) you
should be able to provide your own locale and not break everything if
your locale is consistent.

I haven't had to work with serializing complex numbers but I hadn't
realised how broken it apprears to be.

#include <iostream>
#include <sstream>
#include <complex>
#include <locale>

int main(int argc, char* argv[])
{
std::stringstream sstr;

if (argc 1)
{
sstr.imbue(std::locale(argv[1]));
}

std::complex<doublec1(1.5), c2(1, 5);
std::complex<doublec3, c4;

sstr << c1 << c2;
std::cout << sstr.str() << std::endl;
sstr >c3 >c4;

std::cout << c3 << c4 << std::endl;
}

$ ./a.out
(1.5,0)(1,5)
(1.5,0)(1,5)

OK, that works.

$ ./a.out fr_FR
(1,5,0)(1,5)
(1.5,0)(1.5,0)

Oops!

$ ./a.out en_GB
(1.5,0)(1,5)
(1.5,0)(0,0)

This one surprised me. Attaching a debugger reveals that the comma in
(1,5) is parsed as part of the real part as ',' is a valid thousands
separator. The real read stops when it hits the ')' and then flags a
failure as the thousands seperator was in the wrong place. At least
that's my interpretation of what my implementation is doing.
Jun 13 '07 #29

P: n/a
On Jun 13, 5:09 pm, Diego Martins <jose.di...@gmail.comwrote:
On Jun 13, 10:18 am, James Kanze <james.ka...@gmail.comwrote:
On Jun 13, 9:33 am, Charles Bailey <usenetspa...@hashpling.orgwrote:
there are two C++ important things I never found in a C++ mainstream
book:
- a detailed description/tutorial/pitfall on implementing custom
streams;
- a detailed description/tutorial/pitfall on implementing custom
iterators;
why? :(
I don't know? I wrote two articles about one type of custom
stream, some years ago in C++ Reports; they're available at my
site (http://kanze.james.neuf.fr/articles-en.html). For a long
time, Dietmar Kuehl had some examples at his site, but I don't
know what the status of that is now. And while I've not seen it
myself (I was doing this before the book came out), I've heard
only good about _Standard C++ IOStreams and Locales: Advanced
Programmer's Guide and Reference_, by Angelika Langer and Klaus
Kreft.

In the meantime, you should probably check out Boost::iostream.
While it's not really that difficult to write your own
streambuf, the Boost library makes it exceptionally easy, even
when you want to handle more complicated issues like seeking or
buffering.

--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 13 '07 #30

P: n/a
On Jun 13, 5:21 pm, Charles Bailey <usenetspa...@hashpling.orgwrote:
On 2007-06-13, James Kanze <james.ka...@gmail.comwrote:
On Jun 13, 9:33 am, Charles Bailey <usenetspa...@hashpling.orgwrote:
If you want the change the way in which various types are written out
then you may find that you can achieve what you want by implementing a
local::facet. You might, for instance, decide that integers should
really be serialised in a custom base64 style encoding. You could
then implement num_get and num_out facets. You can use this with the
standard iostreams by creating a new locale (std::locale has methods
for retrieving a copy of either the global locale or the "classic"
one), patching in your custom facets and imbueing (calling
ios_base::imbue) the stream with your custom locale.
That sounds a lot like abuse to me, and is likely to cause
trouble, since more complex objects like std::complex count on a
particular format. (In fact, std::complex doesn't even work
correctly in most European locales. That, I believe, is
considered an error, but I don't think the committee would
recognize it an error if e.g. it didn't work with
num_get/num_put facets which did binary output.)
My example was bad. The usual facets are fairly flexible but in
theory, if you have an obscure locale with an interesting way of
writing numbers that you need to support (or have invented ;) ) you
should be able to provide your own locale and not break everything if
your locale is consistent.
You should be able to, at least within very liberal limits. In
practice, I'm less sure. I would consider something like using
a different base an abuse, and in practice, I'd be sceptical of a
facet which provided a new num_get or num_put (as opposed to
simply a new num_punct). As you say, you should be able to,
but...
I haven't had to work with serializing complex numbers but I hadn't
realised how broken it apprears to be.
It is very, very broken, probably because it doesn't take locale
at all into account. This will be fixed, I hope, in the next
release of the standard; at present, it fails in most of the
locales I normally use.
#include <iostream>
#include <sstream>
#include <complex>
#include <locale>
int main(int argc, char* argv[])
{
std::stringstream sstr;
if (argc 1)
{
sstr.imbue(std::locale(argv[1]));
}
std::complex<doublec1(1.5), c2(1, 5);
std::complex<doublec3, c4;
sstr << c1 << c2;
std::cout << sstr.str() << std::endl;
sstr >c3 >c4;
std::cout << c3 << c4 << std::endl;

}
$ ./a.out
(1.5,0)(1,5)
(1.5,0)(1,5)
OK, that works.
$ ./a.out fr_FR
(1,5,0)(1,5)
(1.5,0)(1.5,0)
Oops!
The normal way of writing a complex in France is "(1,5;1,5)".
For obvious reasons, we don't use a , as a separator.
$ ./a.out en_GB
(1.5,0)(1,5)
(1.5,0)(0,0)
This one surprised me. Attaching a debugger reveals that the
comma in (1,5) is parsed as part of the real part as ',' is a
valid thousands separator.
The whole way thousands separators work probably needs to be
rethought out. The usual thousands separator in France is a
space, which causes no end of problems. (I'm afraid I don't
have a solution to propose for this one. My own input
conversion routines ignore spaces, where ever they appear. But
this means that the user must first parse the text enough to
isolate the number before trying to convert it.)
The real read stops when it hits the ')' and then flags a
failure as the thousands seperator was in the wrong place. At
least that's my interpretation of what my implementation is
doing.
It sounds likely. There should be a means of inhibiting the use
of thousands separators in certain numbers, regardless of the
locale, and this should be activated when reading complex.

--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jun 13 '07 #31

This discussion thread is closed

Replies have been disabled for this discussion.