0

Although I found a lot of stuff about std::fstream on SO, I still can't understand how it operates. Let's see this minimal example:

#include <fstream>
#include <string>

int main()
{
  std::fstream fs{ "somefile.txt", std::fstream::out | std::fstream::in };
  std::string line;

  while (std::getline(fs, line))
  {
    // reads the whole file
  }

  // the purpose is to overwrite the whole file
  fs.seekp(0, std::ios_base::beg); // moves at the beginning
  fs << "Hello world!" << std::endl; // writes in the file

  // possibly other read/write
}

This does not work, it seems that one cannot firstly read, and then write in the same stream according to everything I read about. I know the workaround that consists in closing the file, then opening it with the std::ios_base::trunc flag. However, that seems to be nonsensical: why is there such a limitation? Cannot we technically just overwrite the file after the reading?

w00d
  • 5,416
  • 12
  • 53
  • 85
Boiethios
  • 38,438
  • 19
  • 134
  • 183

2 Answers2

4

The loop iterates until the fail bit gets set. Just clear() the flags prior to the seek:

fs.clear();

If you only want to overwrite the starting bit that is sufficient. If also want to truncate the stream I'd explicitly close() and open() it, where the open() would not set std::ios_base::in.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • Yes, that writes the string, but the whole file is not overwritten. – Boiethios Dec 21 '16 at 14:20
  • @Boiethios: You did not write any code to perform that function. Don't blame fstream for that. – Lightness Races in Orbit Dec 21 '16 at 14:21
  • Why do we need to release the file, then to reopen it? There are operations we do not need normally! – Boiethios Dec 21 '16 at 14:28
  • @Boiethios: until the filesystem libraries are standardized, the only platform independent way to truncate the file is during opening, so there is no workaround. – AndyG Dec 21 '16 at 14:31
  • @AndyG Oh, thank you! So that's it. Could you explain this as answer? – Boiethios Dec 21 '16 at 14:32
  • _"There are operations we do not need normally!"_ When do you not need them? What is this "normally" of which you speak? Are you confusing streams with containers? Regardless of implementation/POSIX constraints, the two are different kinds of things and file truncation has next to no business existing in the `fstream` interface. – Lightness Races in Orbit Dec 21 '16 at 14:34
  • @Boisthios: there may be OSes which allow truncating an open file. I'm pretty sure not all do. Also, the file stream interface is pretty much unchanged since a fairly long time: I could well imagine that popular systems back then did not have a way to truncate an open file. – Dietmar Kühl Dec 21 '16 at 14:34
  • @DietmarKühl I saw that for example http://stackoverflow.com/questions/980283/truncating-a-file-while-its-being-used-linux – Boiethios Dec 21 '16 at 14:40
  • 1
    @Boiethios: which actually does open (and thereby truncate) the file again! Yes, you can open another file stream to truncate the one you have already open. What will happen next is somewhat unclear, though, as the streams are buffered. You may get back some of the buffers, possible preceded by a lot of zero pages (depending on where your file pointer is at this time and how the `std::filebuf` is implemented). – Dietmar Kühl Dec 21 '16 at 14:44
1

After reading the whole file, the fs is now in eof state. You need to clear the state so it can do following IO operations.

apple apple
  • 10,292
  • 2
  • 16
  • 36