2

As far as I understand, fstream allows you to write and read the same opened file. Also it has two "file pointers", one for reading and other for writing. But if I read one line from file first, and then trying to write in it - file doesn't change, even if I use flush() after.

There is a way to fix this - use seekp() and move "file pointer" somewhere. But I don't understand why does it work that way. And there is some strange detail - if I check file pointers with tellp() before and after writing - they actually change their position! Maybe I am mistaken in something, and I will be grateful for any help

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

using namespace std;

int main() {
    fstream file("Output.txt");
    string line = "";

    getline(file, line);
    cout << "Read line: " << line << endl;

    cout << "tellg: " << file.tellg() << endl;
    cout << "tellp: " << file.tellp() << endl;
    cout << "rdstate: " << file.rdstate() << endl;
    cout << "------------------------------- " << endl;

    file.write("test", 4);
    file.flush();
    cout << "After writing:\nrdstate: " << file.rdstate() << endl;
    cout << "tellg: " << file.tellg() << endl;
    cout << "tellp: " << file.tellp() << endl;

    file.close();
    cout << "------------------------------- " << endl;
    cout << "After closing:\nrdstate: " << file.rdstate() << endl;
}

So I have a file:

a
b
c
d

It doesn't change after program worked. There are no any errors according to rdstate()

Program output:

Read line: a
tellg: 3
tellp: 3
rdstate: 0

After writing:
rdstate: 0
tellg: 9
tellp: 9

After closing:
rdstate: 0
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • 1
    It changes the file for me. After running the program `Output.txt` contains `atestd`. `bc` was overwritten by `test`. – Ted Lyngmo Apr 28 '19 at 11:20
  • 1
    @TedLyngmo `tellg: 3`/`tellp: 3` looks for me as if OP is on Windows (where lines end with `\r\n`). What I don't understand is `tellg: 9`/`tellp: 9` after `file.write("test", 4);`. I would expect 3 + 4 = 7 in both cases... – Scheff's Cat Apr 28 '19 at 11:24
  • @Scheff True, it does look like Windows ... and I got the same result as OP :-) – Ted Lyngmo Apr 28 '19 at 11:28
  • yep, it is Windows, Visual Studio 2019... – Kirill Qumorion Apr 28 '19 at 11:47
  • Wow, I compiled the same program with MinGW compiler and its worked! Looks like the problem in the VStudio compiler.. – Kirill Qumorion Apr 28 '19 at 11:59
  • 1
    Couldn't reproduce with `g++` in cygwin BUT _could_ reproduce with VS2013. (Except that the 2nd `tellg`/`tellp` reported 12 in my case.) Found [SO: How is std::fstream with both in and out supposed to work?](https://stackoverflow.com/a/21917273/7478597) with _When you perform a read after a write or vice-versa, the stream should be repositioned back._ which seems to give a hint... – Scheff's Cat Apr 28 '19 at 12:11
  • @Scheff This tellg / tellp result is unclear for me too. But if I change `CRLF` with `LF` in a text editor and use mingw instead of visual studio compiler the tellp result will be correct: 2 before write and 6 after – Kirill Qumorion Apr 28 '19 at 12:13
  • If I change `Output.txt` to Unix line endings, I get in VS2013 `-1` and `8` from `tellg`/`tellp`. With `fstream("Output.txt", ios::in | ios::out | ios::binary);`, it's `2` and `8` which is less disturbing. ;-) – Scheff's Cat Apr 28 '19 at 12:18
  • Please, see the link above and the cited sentence: Inserting a `file.seekp(file.tellp());` before `file.write("test", 4);`, it works in VS2013 also. – Scheff's Cat Apr 28 '19 at 12:20
  • @Scheff, thank you! Seems to me this behavior depends on the compiler. So with Visual Studio it's necessary to use `seekp(tellp())` before different operation with fstream. – Kirill Qumorion Apr 28 '19 at 12:28
  • I looked through cppreference for a while to find something I could cite but I failed. For me, it seems that _When you perform a read after a write or vice-versa, the stream should be repositioned back._ (cited from [SO: How is std::fstream with both in and out supposed to work?](https://stackoverflow.com/a/21917273/7478597)) is relevant here. I'm not sure whether this is just compiler dependent. I even suspect it is Undefined Behavior and the suggested fix `file.seekp(file.tellp());` before `file.write("test", 4);` is good for any compiler. – Scheff's Cat Apr 28 '19 at 12:38
  • Found a possible duplicate [SO: Reading and writing to the same file using the same fstream](https://stackoverflow.com/a/17567454/7478597) (and the accepted answer supports my suspicion. Though it also supports that this might be relevant for MS VC++ only.) – Scheff's Cat Apr 28 '19 at 12:47
  • @Scheff Yep, my question is a duplicate indeed, thank you anyway) – Kirill Qumorion Apr 28 '19 at 13:17

1 Answers1

1

It seems to me that the problem in the Visual Studio compiler (I am using 2019 version, but @Scheff could reproduce this kinda bug in VS2013).

So the solution is inserting a file.seekp(file.tellp()) before the writing after reading and vice-versa. Or you can just use another compiler:-)