使用 QFile::write 的正确方法?

proper way to use QFile::write?

本文关键字:方法 QFile write 使用      更新时间:2023-10-16

我需要将n字节写入文件,我有QTemporaryFile, 我应该如何写入这些字节?

我阅读了QIODevice::write文档:

qint64 QIODevice::write(const char *data, qint64 maxSize( Write at 从数据到设备的最大大小数据字节数。返回数字 实际写入的字节数,如果发生错误,则为 -1。

所以看起来我需要循环来写入字节,因为没有受赠人 它写入所有字节,它可以在写入k字节后返回控制权, 哪里k<n.>

我可以从TemporaryFile创建QDataStream,但QDataStream::writeRawData函数具有相同的限制:

int QDataStream::writeRawData(const char *s, int len( Write len bytes 从 s 到流。返回实际写入的字节数,或 错误时为 -1。数据未编码。

所以Qt中没有确切写入n字节或返回错误的函数?

这是一件奇怪的事情...

一方面:

  • QFile::write的实现是基于writeDataQIODevice::writeData抽象方法的文档说:

    重新实现此函数时,此函数在返回之前写入所有可用数据非常重要。[接下来的几句话,据我所知,这很重要,因为依赖类QDataStream其高级方法(不返回写入的字节数(不执行循环。

    所以,我们似乎也不需要骑自行车。

  • 实际上,QFileDevice::writeData(覆盖QIODevice::writeData(似乎调用了QFSFileEnginePrivate::writeFdFh方法(特别是:QIODevice::writeQFileDevice::writeDataQFSFileEngine::writeQFSFileEnginePrivate::nativeWriteQFSFileEnginePrivate::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中的更高级别的方法,如QTextStreamQDataStream中的方法(例如,参见QTextStream::operator<<(const QString &string)和底层方法,QDataStream::operator<<(const char *s)和底层方法(,不会自己做循环(而是依靠QFSFileEnginePrivate::writeFdFh中的循环(。

因此,看起来Qt并没有遵循典型的POSIX约定,例如"读取/写入少于请求不一定是错误,只需重试即可"。相反,QFile的方法被调整为仅在出错的情况下才读取/写入少于请求的。所以通常你不应该自己骑自行车QFile::write

但是,另一方面,根据2018年5月"兴趣"Qt邮件列表中的一个线程"QFile::write(const QByteArray&(不写入所有数据?",在某些情况下,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的精神是"只有在出错的情况下QIODevice::write才会写入少于请求的,因此不需要外部循环"。这就是为什么Qt开发人员既没有为QIODevice::write周围的外部循环提供方便的方法,也没有在QTextStreamQDataStream等高级类中QIODevice::write外部循环
  • 然而,他们不敢承诺这种方法会奏效(永远并且对所有QIODevice后代(。这就是为什么文件没有提供这样的保证。(它仅对QIODevice::writeData实施者应用义务,而不对QIODevice::write用户应用特权
  • 我个人的选择是不在QFile::write周围进行外部骑行。

在没有错误但写入的字节少于n个的情况下,您如何建议撤消某些字节的写入?特别是如果文件中已有数据(以前的writes成功,或者因为您正在追加(。

如果没有外部操作,任何进一步尝试写入未写入所有n字节的文件也可能失败或写入 0。浮现在脑海中的情况是可用磁盘空间耗尽。