Search code examples
c++qtfileqfile

QFile: multiple handles to same physical file do not write all data


I was wondering how QFile behaves when multiple handles are opened to the same file (using C++ in Visual Studio 2013 on Windows 7), so I wrote the following little program:

  QFile file("tmp.txt");
  file.open(QIODevice::WriteOnly | QIODevice::Truncate);
  QTextStream ts(&file);
  ts << "Hallo\n";

  QFile file2("tmp.txt");
  file2.open(QIODevice::WriteOnly | QIODevice::Append);
  QTextStream ts2(&file2);
  ts2 << "Hallo 2\n";

  file.close();

  ts2 << "Hello again\n";

  file2.close();.

This produces the following output in file tmp.txt:

Hallo 2
Hello again

So the first Hallo statement got lost. If I do a ts.flush() right after the ts << "Hallo\n" this does not happen, which makes me think that the statement got lost in the internal buffers of QString or it was overwritten by the subsequent output statements. However, I want to use QFile in a logging framework, so I don't want to always flush, as this would decrease the performance.

I also tried the same thing with std::basic_ostream<char> instead of QFile:

  std::basic_ofstream<char> file;
  file.open("tmp.txt", std::ios_base::out | std::ios_base::ate | std::ios_base::app);
  file << "Hallo\n";

  std::basic_ofstream<char> file2;
  file2.open("tmp.txt", std::ios_base::out | std::ios_base::ate | std::ios_base::app);
  file2 << "Hallo 2\n";

  file.close();

  file2 << "Hello again\n";

  file2.close();

which outputs as I would expect:

Hallo
Hallo 2
Hello again

So what is the problem with the QFile example? Is QFile not intended to be used with multiple handles pointing to the same file or what is going on here exactly? I thought that my use case is quite a common one, so I'm a bit surprised to find this behaviour. I couldn't find more specifics in the Qt documentation. I've read here that Qt opens the file in shared mode, so this shouldn't be a problem.

I eventually want to use QFile for logging (where access to the function that does the actual writing is of course synchronized), but this little example worries me that some log statements might get lost on the way. Do you think it would be better to use STL streams instead of QFile?

Edit As it was pointed out, std::endl causes a flush, so I changed the STL example above to only use \n which according to here does not cause a flush. The behavior described above is unchanged, though.


Solution

  • I seems you want it both ways.

    If you want several write buffers and don't want to flush them, it's hard to be sure of having all the writes in the file, and in the right order. Your small test with std::basic_ostream is not a proof: will it work with larger writes ? Will it work on other OSes ? Do you want to risk your process for a (yet unproven) speed gain ?