c++ - 使用 QFile::write 的正确方法?
问题描述
我需要将n
字节写入文件并且我有QTemporaryFile
,我应该如何写入这些字节?
我阅读QIODevice::write
了文档:
qint64 QIODevice::write(const char *data, qint64 maxSize) 将数据中最多 maxSize 个字节的数据写入设备。返回实际写入的字节数,如果发生错误,则返回 -1。
所以看起来我需要循环来写入字节,因为没有被授权者写入所有字节,它可能会在写入字节后返回控制k
,其中k
< n
。
我可以QDataStream
从创建TemporaryFile
,但QDataStream::writeRawData
函数有同样的限制:
int QDataStream::writeRawData(const char *s, int len) 将 len 字节从 s 写入流。返回实际写入的字节数,错误时返回 -1。数据未编码。
所以没有函数Qt
可以准确写入n
字节或返回错误?
解决方案
这是一件很奇怪的事情……</p>
一方面:
QFile::write
的实现基于writeData
,抽象方法的文档QIODevice::writeData
说:重新实现此函数时,重要的是此函数在返回之前写入所有可用数据。[接下来的几句话,据我所知,这很重要,因为
QDataStream
在其高级方法中的依赖类(不返回写入的字节数)不执行循环。]所以,我们似乎也不需要骑自行车。
真的,
QFileDevice::writeData
(覆盖QIODevice::writeData
)似乎调用了QFSFileEnginePrivate::writeFdFh
方法(特别是:QIODevice::write
→QFileDevice::writeData
→QFSFileEngine::write
→QFSFileEnginePrivate::nativeWrite
→QFSFileEnginePrivate::writeFdFh
),它自己执行循环:if (fh) { // Buffered stdlib mode. size_t result; do { result = fwrite(data + writtenBytes, 1, size_t(len - writtenBytes), fh); writtenBytes += result; } while (result == 0 ? errno == EINTR : writtenBytes < len); } else if (fd != -1) { // Unbuffered stdio mode. SignedIOType result; do { // calculate the chunk size // on Windows or 32-bit no-largefile Unix, we'll need to read in chunks // we limit to the size of the signed type, otherwise we could get a negative number as a result quint64 wantedBytes = quint64(len) - quint64(writtenBytes); UnsignedIOType chunkSize = std::numeric_limits<SignedIOType>::max(); if (chunkSize > wantedBytes) chunkSize = wantedBytes; result = QT_WRITE(fd, data + writtenBytes, chunkSize); } while (result > 0 && (writtenBytes += result) < len);
Qt 中的高级方法,如
QTextStream
and中的方法QDataStream
(例如 seeQTextStream::operator<<(const QString &string)
和底层方法,QDataStream::operator<<(const char *s)
以及底层方法),不会为自己执行循环(QFSFileEnginePrivate::writeFdFh
而是依赖于循环)。
因此,看起来 Qt 没有遵循典型的 POSIX 约定 a-la “读/写少于请求不一定是错误,只是重试”。相反QFile
,只有在出错的情况下,才将方法调整为读/写少于请求。所以通常你不应该在QFile::write
自己周围骑自行车。
但是,另一方面,根据线程“QFile::write(const QByteArray&) 不会写入所有数据?” 在2018 年 5 月的“兴趣”Qt 邮件列表中,存在QFile::write
写入少于请求且循环QFile::write
使用的情况。至少它们存在于 2018 年 5 月,Alexander Golks 说他在升级到 Qt 5.6.4 后无法重现该问题(但我不知道究竟修复/更改了什么,因为QFSFileEnginePrivate::writeFdFh
在那之前的很多年都是循环的)。但对我来说主要的冲击不是QFile::write
在一个较旧的 Qt 版本中,没有外部循环是不够的(谁知道,也许这是一个已修复的 Qt 错误或必须通过其他方式解决的硬件/驱动程序问题),但直接接收邮件的邮件列表成员参与Qt 开发(例如Thiago Macieira)的立场是a-la “不要指望QFile::write
什么都写,要骑自行车”。
结论。我不知道该说些什么。我的猜测是:
- Qt的精神是“<code>QIODevice::write 只会在出错的情况下写入少于请求的内容,因此不需要外部循环”。这就是为什么 Qt 开发人员既没有提供方便的外部循环方法,
QIODevice::write
也没有QIODevice::write
在更高级别的类(QTextStream
如QDataStream
. - 然而,他们不敢保证这种方法会奏效(总是对所有
QIODevice
后代)。这就是为什么文件信没有提供这样的保证。(它仅适用于实施者的义务,QIODevice::writeData
而不适用于用户的特权QIODevice::write
。) - 我个人的选择是不做外围骑行
QFile::write
。
推荐阅读
- azure - 即使凭据正确,Azure Log Analytics API 也会返回 InvalidAuthorization
- flutter - Dart 在嵌套数据类上使用折叠来获取计数总和
- intershop - 如何告诉页面缓存忽略某些 URL 参数
- database - woocommerce 为每个客户添加 meta_key 和 meta_value
- firebase - 当我登录“人员”并终止应用程序时如何防止“管理员”登录(FLUTTER)
- azure-data-factory - 使用带有语言环境和格式参数的 toInteger 函数
- styled-components - 样式组件中是否有扩展 createGlobalStyle
- php - 设置值时访问当前数组键
- c# - Blazor WASM 表排序问题
- java - 将 Guava 谓词转换为 Java 8 谓词