Search code examples
c++11binaryfiles

C++ - Can't overwrite file with a single byte in binary mode after reading it (Windows 10)


EDIT: I have a problem with this little piece of code. I'm new to C++ and I need to understand how to write a byte (or a multiple bytes) inside a file in binary mode.

With this code I'm reading the first 11 bytes of foo.txt. Inside foo.txt there is this string "Hello World!!!". On the console we see "Hello World". Until here it's all ok!

The problem is that I can't overwrite the entire file (or few bytes) after reading into, why? On Ubuntu it overwrites the byte in position 11, not on Windows. On Windows it doesn't do nothing!

The file is opened in read/write mode with parameters ios_base::in | ios_base::out. When I use file.write() it should overwrites the data with byte 3F (in ASCII the string "?"). It doesn't happen, why?

PLEASE TRY TO RUN THIS CODE! (change workingDirectory)

Thanks

#include <iostream>
#include <string>
#include <fstream>

using namespace std;

int main()
{
    string workingDirectory = "C:\\Users\\francesco\\Documents\\Test\\";
    string inputFile = workingDirectory + "foo.txt";
    fstream file;
    file.open(inputFile, ios_base::in | ios_base::out | ios_base::binary);
    char *buffer = new char [11];
    file.read(buffer, 11);

    cout << "Track:" << endl;
    for (int i = 0; i < 11; i++)
    {
        cout << buffer[i];
    };

    cout << endl;
    delete[] buffer;

    if (file.is_open())
    {
        cout << "The file is still open!" <<  endl;
        int num = 63; // 0x3F ASCII --> ?
        file.write((char*)&num, 1);
    }
    else
    {
        cout << "We shoudln't reach this part of code!" << endl;
    }

    file.close();

    return 0;
}

At the moment I resolved the problem closing and reopening file (or seek again to byte 11). It is interesting to know why on Windows we have to do this after reading operation


Solution

  • I found the problem, the library has a different (incorrect) behaviour with different OSes.

    EDIT:

    From C11 standard, ISO/IEC 9899:2011:

    ...input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file.

    Read here also for C++ library:

    Once a file has been opened in read and write mode, the << operator can be used to insert information into the file, while the >> operator may be used to extract information from the file. These operations may be performed in any order, but a seekg or seekp operation is required when switching between insertions and extractions. The seek operation is used to activate the stream's data used for reading or those used for writing (and vice versa). The istream and ostream parts of fstream objects share the stream's data buffer and by performing the seek operation the stream either activates its istream or its ostream part. If the seek is omitted, reading after writing and writing after reading simply fails.

    These are the cases:

    1. On Windows it overwrites first byte only if we don't previously read the first 11 bytes and opened the file in read/write mode
    2. On Windows it CAN'T overwrites byte in position 11 (no errors) if we previously read the first 11 bytes and opened the file in read/write mode
    3. On Windows after reading the first 11 bytes we have to seek to position 11 in order to overwrite byte in position 11
    4. On Ubuntu it overwrites byte in position 11 also if we previously read the first 11 bytes and opened the file in read/write mode
    5. On both OS if we open the file with ios_base::out only parameter it overwrites the entire file, not if we use ios_base::in also

    At the moment I resolved the problem closing and reopening file (and/or seek again to byte 11).

    It is interesting to know why on Windows only we have to do this after reading operation.