views:

801

answers:

3

Hi,

I just took some older code of a file reader that had been developed under Linux and tried to use that very same code in my Windows project compiled with MSVC++7.1. The code compiled without any problems, but the file seemed to be empty according to the file reader on Windows.

I tracked the problem down to ifstream.readsome() that didn't read anything from the file, without setting any error flags on the stream. The code provided below compiles on either Linux and Windows, but Linux it works as expected.

The code opens a file and reads the first 512 bytes of the file one time with read() and one time with readsome(). Both results are stored in two vectors that are compared at the end of the program. The expected result would be that the two vectors are equal.

The result output of the program on Windows XP is posted below the source code.

If anyone has any ideas or guesses what might go wrong in this code, I'd love to hear them.

thanks, Norbert

Full source code of demo:

#include <iostream>
#include <fstream>
#include <vector>
#include <cassert>

int main()
{
  const size_t BUFFER_SIZE(512);

  std::ifstream in("some.file", std::ios::in | std::ios::binary);
  if(in.is_open())
  {
    std::vector<char> buf1(BUFFER_SIZE);
    std::vector<char> buf2(BUFFER_SIZE);
    assert(buf1 == buf2);

    if(in.seekg(0, std::ios_base::beg).good())
    {
      //read BUFFER_SIZE bytes from the file using read()
      if(in.read(&buf1[0], buf1.size()).eof())
      {
        std::cerr << "read() only read " << in.gcount() << " bytes." << std::endl;
      }
      else
      {
        std::cout << "read() could read all 512 bytes as expected." << std::endl;
      }
      if(!in.good())
      {
        std::cerr << "read() set an error flag in ifstream." << std::endl;
      }
    }
    else
    {
  std::cerr << "Can not test read()." << std::endl;
    }
    if(in.seekg(0, std::ios_base::beg).good())
{
      //read BUFFER_SIZE bytes from the file using readsome()
      std::streamsize bytesRead = in.readsome(&buf2[0], buf2.size());
      if(bytesRead != BUFFER_SIZE)
      {
        std::cerr << "readsome() only read " << bytesRead << " bytes." << std::endl;
      }
      else
      {
        std::cout << "readsome() could read all 512 bytes as expected." << std::endl;
      }
      if(!in.good())
      {
        std::cerr << "readsome() set an error flag in ifstream." << std::endl;
      }
    }
    else
    {
      std::cerr << "Can not test readsome()." << std::endl;
    }

    //should read from the same file, so expect the same content
    assert(buf1 == buf2);
  }

  return 0;
}

Output on Windows XP:

read() could read all 512 bytes as expected.
readsome() only read 0 bytes.
Assertion failed: buf1 == buf2, file [...], line 60
+1  A: 

readsome() is there to make non blocking reads, as what precisely that means is implementation defined (or defined by your custom streambuf member showmanyc()), behaviour can vary. Both seem correct to me.

AProgrammer
+1  A: 

Take a look at the discussion here

Naveen
Thanks, that was well explained there. Seems I have to rewrite the stuff to use read().
A: 

And the assertion "assert(buf1 == buf2);" fails when compiling in debug mode because buf1 and buf2 were only told to reserve memory (that is only to allocate memory, not to initialize it), and the operator == actually compares two buffers having undefined values.

As for "read(...)" and "readsome(...)", my advice is to stick with "read(...)" for most cases.