QFile:同一物理文件的多个句柄不会写入所有数据

时间:2016-02-15 14:24:15

标签: c++ qt file qfile

我想知道当多个句柄打开到同一个文件时QFile如何表现(在Windows 7上的Visual Studio 2013中使用C ++),所以我编写了以下小程序:

  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();.

这会在文件tmp.txt中生成以下输出:

Hallo 2
Hello again

所以第一个Hallo语句丢失了。如果我在ts.flush()之后立即执行ts << "Hallo\n"这不会发生,这使我认为该语句在QString的内部缓冲区中丢失,或者被后续输出语句覆盖。但是,我想在日志记录框架中使用QFile,因此我不想总是刷新,因为这会降低性能。

我也使用std::basic_ostream<char>而不是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();

按照我的预期输出:

Hallo
Hallo 2
Hello again

那么QFile示例有什么问题? QFile是不是要用于指向同一文件的多个句柄或者这里发生了什么?我认为我的用例很常见,所以我发现这种行为有点惊讶。我无法在Qt documentation中找到更多细节。我已阅读here Qt以共享模式打开文件,因此这不应该是一个问题。

我最终希望使用QFile进行日志记录(对实际写入的函数的访问当然是同步的),但是这个小例子让我担心某些日志语句可能会丢失。您认为使用STL流而不是QFile会更好吗?

修改 正如指出的那样,std::endl导致刷新,所以我将上面的STL示例更改为仅使用\n Feret's diameter (8, 16,32 or 64),根据here不会导致刷新。但是,上述行为没有改变。

3 个答案:

答案 0 :(得分:1)

我似乎想要两种方式。

如果你想要几个写缓冲区不想刷新它们,很难确保文件中的所有写入都是正确的,并且顺序正确。 您使用std::basic_ostream进行的小型测试不是证明:它是否适用于较大的写入?它会在其他操作系统上运行吗?您是否希望冒险(或未经证实)速度增加您的过程?

答案 1 :(得分:0)

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

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

  file.close();

  ts2 << "Hello again\n";

  file2.close();

试试这个,我改了它,所以Truncate没有被WriteOnly调用。傻我没看过那个。 {UPDATE}

QIODevice::WriteOnly    0x0002  The device is open for writing. Note that this mode implies Truncate.
QIODevice::Truncate 0x0008  If possible, the device is truncated before it is opened. All earlier contents of the device are lost.

阅读来源:http://doc.qt.io/qt-5/qiodevice.html#OpenModeFlag-enum

答案 2 :(得分:0)

有几件可疑的事情正在发生。对于初学者,您将引入两个级别的缓冲。

  1. 首先,QTextStream有一个内部缓冲区,您可以通过调用flush来刷新它。

  2. 其次,QFile也在缓冲(或者,更好的是,它使用了库中的缓冲API - fopenfwrite等等。将QIODevice::Unbuffered传递给open,使其使用未缓冲的API(openwrite,...)。

  3. 现在因为这非常容易出错,所以QTextStream :: flush actually flushes also the underlying file device

    另外,你传递的WriteOnly | Append没有意义。这只是两者中的一个。

    但请注意,您的写入仍可能会交错。 POSIX.1-2013 says that

      

    如果在一个操作中写入的全部量与来自任何其他进程的数据不交错,则写入是原子的。当有多个写入器将数据发送到单个读取器时,这很有用。应用程序需要知道可以预期以原子方式执行写入请求的大小。此最大值称为{PIPE_BUF}。

    (在Windows上我不知道)。