QFile:同一物理文件的多个句柄不会写入所有数据
QFile: multiple handles to same physical file do not write all data
我想知道当打开多个句柄到同一个文件时QFile
的行为(在Windows 7上使用Visual Studio 2013中的C++(,所以我写了以下小程序:
QFile file("tmp.txt");
file.open(QIODevice::WriteOnly | QIODevice::Truncate);
QTextStream ts(&file);
ts << "Hallon";
QFile file2("tmp.txt");
file2.open(QIODevice::WriteOnly | QIODevice::Append);
QTextStream ts2(&file2);
ts2 << "Hallo 2n";
file.close();
ts2 << "Hello againn";
file2.close();.
这会在文件 tmp.txt 中生成以下输出:
Hallo 2
Hello again
所以第一个Hallo
声明丢失了。如果我在ts << "Hallon"
后立即执行ts.flush()
,则不会发生这种情况,这使我认为该语句在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 << "Hallon";
std::basic_ofstream<char> file2;
file2.open("tmp.txt", std::ios_base::out | std::ios_base::ate | std::ios_base::app);
file2 << "Hallo 2n";
file.close();
file2 << "Hello againn";
file2.close();
输出如我所期望的那样:
Hallo
Hallo 2
Hello again
那么QFile
的例子有什么问题呢?QFile
不是打算与指向同一文件的多个句柄一起使用,还是这里到底发生了什么?我认为我的用例很常见,所以我发现这种行为有点惊讶。我在Qt文档中找不到更多细节。我在这里读到Qt以共享模式打开文件,所以这应该不是问题。
我最终想使用 QFile
进行日志记录(当然,对执行实际写入的函数的访问是同步的(,但这个小例子让我担心某些日志语句可能会在途中丢失。您认为使用 STL 流而不是QFile
更好吗?
编辑正如有人指出的那样,std::endl
会导致刷新,因此我将上面的 STL 示例更改为仅使用根据此处不会导致刷新的n
。但是,上述行为保持不变。
我似乎你想要两种方式。
如果需要多个写入缓冲区并且不想刷新它们,则很难确定所有写入都按正确的顺序在文件中。你用std::basic_ostream
的小测试不能证明:它适用于更大的写入吗?它会在其他操作系统上运行吗?您想冒险提高(尚未证实的(速度吗?
有几件可疑的事情正在发生。对于初学者,您将引入两个级别的缓冲。
-
首先,QTextStream有一个内部缓冲区,您可以通过调用
flush
来刷新它。 -
其次,QFile 也是缓冲的(或者,更好的是,它使用库中的缓冲 API --
fopen
、fwrite
等(。将QIODevice::Unbuffered
传递给open
,使其使用未缓冲的 API(open
、write
、...(。
现在,由于这非常容易出错,QTextStream::flush实际上也会刷新底层文件设备。
此外,您正在传递WriteOnly | Append
这没有意义。这只是两者之一。
但是,请注意,您的写入仍可能交错。POSIX.1-2013 说
如果一个操作中写入的全部量不与来自任何其他进程的数据交错,则写入是原子的。当有多个写入器将数据发送到单个读取器时,这很有用。应用程序需要知道以原子方式执行的写入请求预期有多大。此最大值称为 {PIPE_BUF}。
(在Windows上我不知道(。
QFile file("tmp.txt");
file.open(QIODevice::WriteOnly | QIODevice::Truncate);
QTextStream ts(&file);
ts << "Hallon";
QFile file2("tmp.txt");
file2.open(QIODevice::Append);
QTextStream ts2(&file2);
ts2 << "Hallo 2n";
file.close();
ts2 << "Hello againn";
file2.close();
试试这个,我更改了它,以便截断不会被 WriteOnly 调用。傻乎乎的我没读过那个。{更新}
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
- 外壳包装器句柄/执行交互式命令管道C++ UNIX
- 如何获取边缘窗口句柄 (HWND)?
- 枚举进程模块在有效句柄上返回无效句柄
- 在 c/c++ 中打开 PhysicalDrive 的句柄并写入 MBR 的 linux 等效是什么?
- 从运行服务的应用程序代码中提取窗口句柄
- 在读取文件后重置句柄
- 是否有像地图这样的C++结构,但我得到的不是值的键,而是值的句柄?
- Microsoft ODBC 无法创建有效的句柄
- 我是否可以使用 win32 句柄以编程方式记录发送到/接收到 USB/COM 的内容
- 获取特定进程的句柄数
- C++ 创建 NdisProt 驱动程序的句柄
- 是否需要关闭来自 WinHTTP 异步的句柄?
- 句柄OK全部崩溃
- 我需要通过窗口句柄(HWND)获取文件,我该怎么办?
- 什么是 C# 等同于C++句柄
- 未知C++错误:致命错误:glibc检测到无效的stdio句柄
- 获取现有进程句柄
- GetModuleHandle() 无法检索由 "notepad.exe" 加载的"advapi32.dll"的句柄
- QFile:同一物理文件的多个句柄不会写入所有数据
- 如何根据要写入的数据类型动态选择文件句柄