tags:

views:

693

answers:

3

I knew I should never have started using c++ io, the whole "type safety" argument is a red herring (does anyone really find that it's one of their most pressing problems?). Anyhow, I did, and discovered a strange difference between ifstreams and FILE*s and plain old file descriptors: ifstreams cannot read from a device. Can anyone think of a reason why?

const char* path = "/dev/disk3";
char  b;

// this works
FILE* f= fopen(path, "rb");
int i = fread(&b, 1, 1, f);  // returns 1, success!

// this does not work
ifstream cf(path, ios::binary);
cf.read(&b, 1);
bool  good = cf.good(); // returns false, failure.
A: 

I have found random issues like this in C++ I/O for years. It has always seemed like a backwards step to me.

I haven't tried it, but you might want to look at what Boost has to offer:

http://www.boost.org/doc/libs/1_36_0/libs/iostreams/doc/index.html

Lou Franco
+3  A: 

Works fine for me, its not a problem inherent to c++ stream file I/O as you seem to think.

Maybe try adding ios::in to the openmode flags. According to 27.8.1.6 of the standard, it is required to or with ios::in so this probably won't do anything.

Try checking which bit is actually set - instead of calling good(), try checking bad(), eof(), and fail() individually. This might give a clue as to what the error was.

Greg Rogers
Works in your implementation and not in mine = non portable. I "downgraded" to FILE* and everything's working fine.Adios c++ streams, can't say it's been nice knowing you.
Rhythmic Fistman
I had tried or-ing in ios::in, but no luck.
Rhythmic Fistman
Afterwards, the flags aregood = 0eof = 0fail = 1AND... perror says "Invalid argument".I wonder why.
Rhythmic Fistman
Getting interesting, no? Almost as much fun as "Kon and Bal".
Rhythmic Fistman
+2  A: 

The device is unbuffered and must be read from in 512 byte multiples. ifstream does it's own buffering and strangely decided to read 1023 bytes ahead, which fails with "Invalid argument". Interestingly, this ifstream is implemented on top of a FILE*. However, FILE* left to its own devices was reading ahead using a nicer, rounder number of bytes.

Thanks to dtrace for vital clues. I guess we'll never know if the folk who thought they knew answer but didn't want to say were right.

Rhythmic Fistman
So, in other words, the `FILE*` version was only working by accident because of the underlying choice of buffer size. If you can control the buffer size for a C++ stream, then it would probably work just as well. The `basic_filebuf::setbuf` function looks like it might be relevant.
Rob Kennedy
Exactly right, FILE* only worked through sheer luck, so I dropped down to the file descriptor interface. Not before ripping out all the iostream code, though. I don't miss it. Hope that's not too inflammatory for SO-09! Thanks for the comment.
Rhythmic Fistman