首页 > 解决方案 > 使用 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字节或返回错误?

标签: c++qt5

解决方案


这是一件很奇怪的事情……</p>

一方面:

  • QFile::write的实现基于writeData抽象方法的文档QIODevice::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 中的高级方法,如QTextStreamand中的方法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在更高级别的类(QTextStreamQDataStream.
  • 然而,他们不敢保证这种方法会奏效(总是对所有QIODevice后代)。这就是为什么文件没有提供这样的保证。(它仅适用于实施者的义务,QIODevice::writeData而不适用于用户的特权QIODevice::write。)
  • 我个人的选择是不做外围骑行QFile::write

推荐阅读