0

I have tried to read a file by using istream& read (char* s, streamsize n). I have read the description at: http://www.cplusplus.com/reference/istream/istream/read/ saying

If the input sequence runs out of characters to extract (i.e., the end-of-file is reached) before n characters have been successfully read, the array pointed to by s contains all the characters read until that point, and both the eofbit and failbit flags are set for the stream.

Because of that I have put the n with a very large number because I trust the caller that able to allocate enough buffer to read. But I always receive 0 read, I have tried following code to read txt file with 90 bytes:

std::wstring name(L"C:\\Users\\dle\\Documents\\01_Project\\01_VirtualMachine\\99_SharedFolder\\lala.txt");
std::ifstream ifs;
ifs.open(name, ifstream::binary | ifstream::in);
if (ifs)
{
    // get length of file:
    ifs.seekg(0, ifs.end);
    int length = ifs.tellg();
    ifs.seekg(0, ifs.beg);
    char *buffer = new char[length];


    ifs.read(buffer, UINT32_MAX);
    int success = ifs.gcount();
    cout << "success: " << success << endl;
    cout << "size: " << size;
    ifs.close();
}

I even tried with smaller number, eg: 500,000 and it still failed. I have realized that the "n" and the size of file related somehow, the "n" could not be larger than file size too much or else it will read empty....

I know we could fix that easily by putting correct size to read() but I wonder why it happened like that? I should read till EOF then stop right? Could anyone explain to me why please?

EDIT: I just simply want to read to EOF by utilizing istream& read without caring about file size. According to the definition of istream& read(char*s, streamsize n)it should work.

16
  • 4
    How big is your file? If it is more than 90 bytes, you have undefined behavior and any result is valid. Commented May 7, 2020 at 4:42
  • 1
    try reading 90 bytes instead of UINT32_MAX Commented May 7, 2020 at 4:46
  • 1
    @DucLe Extracting the characters is not the same as allocating a buffer to put them in. Read will extract the characters but it assumes that you have created a buffer to put them in. Trust me, you are just mistaken. As user207421 says you need to write a loop and allocate the buffer yourself. Commented May 7, 2020 at 7:33
  • 1
    @DucLe Three different people have told you that you are mistaken, and your program is failing, what more evidence do you need? Commented May 7, 2020 at 7:38
  • 1
    @DucLe In the question you said that you tried with smaller numbers and it failed, but in the comments you said that it you tried with smaller numbers and it succeeded. That also confused me. Commented May 7, 2020 at 7:56

1 Answer 1

1
ifs.read(buffer, UINT32_MAX);

The second parameter to fstream::read is std::streamsize, which is defined as (emphasis mine)...

...a signed integral type...

I therefore guess (as I don't have a Windows environment to test on at this point) that you're working on a machine where std::streamsize is 32bit, and you're looking at your UINT32_MAX ending up as a -1 (and @john testing on a machine where sizeof( std::streamsize ) > 4 so that his UINT32_MAX doesn't wrap into the negative.)

Try again with std::numeric_limits< std::streamsize >::max()... or even better yet, use length because, well, you have the file size right there and don't have to rely on the EOF behavior of fstream::read to save you.


I am not sure whether C++ changed the definition of streams from what the C standard says, but note that C's definition on binary streams states that they...

...may, however, have an implementation-defined number of null characters appended to the end of the stream.

So your, or the user's, assumption that a buffer big enough to hold the data written earlier is big enough to hold the data read till EOF might actually fail.

Sign up to request clarification or add additional context in comments.

5 Comments

I think in the real code the OP does not have the length. So the correct length to use is std::numeric_limits<std::streamsize>::max()
@john: Thanks, edited that max() in. I guess I'm doing too much C right now. :-D
The streamsize in my system is defined as using streamsize = long long; so that UNIT32_MAX should not cause any problem. I think your comment about the null characters appended to end of stream may be the root cause of this. Why I am checking for this is because I saw an old code in my project doing this way but still works for years until I touch them. I suspect that they may have some setting on compiler to stop putting null characters to end of stream or using older compiler version..
@DucLe: The fun of code relying on unspecified, implementation-defined, or downright undefined behavior. ;-) Better playing it safe, always.
@DevSolar I am still not sure about the actual root cause of it, but interesting things is that code works well with __MSC_VER = 1800 (VS2013) and fails with __MSC_VER >= 1910 (VS2017) (I think it will also fail for 1900 as well) It seems that newer compiler has some optimization which causing the problem with this code. Thanks so much for your support :) (anyway I have fixed this issue to read only <= file size)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.