c++ - 使用 QFile::write 的正确方法?

标签 c++ qt5

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

我阅读了QIODevice::write 文档:

qint64 QIODevice::write(const char *data, qint64 maxSize) Writes at most maxSize bytes of data from data to the device. Returns the number of bytes that were actually written, or -1 if an error occurred.

所以看起来我需要循环来写字节,因为没有被授予者 它写入所有字节,它可能会在写入 k 字节后返回控制权, 其中 k <n

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

int QDataStream::writeRawData(const char *s, int len) Writes len bytes from s to the stream. Returns the number of bytes actually written, or -1 on error. The data is not encoded.

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

最佳答案

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

一方面:

  • QFile::write的实现基于 writeData , 和 documentation for the QIODevice::writeData abstract method说:

    When reimplementing this function it is important that this function writes all the data available before returning. [The next few sentences, as far as I understand them, tell that that's important, because the relying class QDataStream in its high-level methods (which don't return a number of bytes written) don't do the cycling.]

    所以,看来我们也不需要骑自行车了。

  • 真的,QFileDevice::writeData (覆盖 QIODevice::writeData )似乎调用 QFSFileEnginePrivate::writeFdFh方法(具体为:QIODevice::writeQFileDevice::writeDataQFSFileEngine::writeQFSFileEnginePrivate::nativeWriteQFSFileEnginePrivate::writeFdFh ),其中does the cycling by itself :

    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 中的方法和 QDataStream (例如,参见 QTextStream::operator<<(const QString &string) and the underlying methods QDataStream::operator<<(const char *s) and the underlying methods ),不要自己骑自行车(而是依靠 QFSFileEnginePrivate::writeFdFh 中的自行车)。

因此,看起来 Qt 不遵循典型的 POSIX 约定 a-la“读/写少于请求不一定是错误,只需重试”。相反 QFile的方法被调整为只在错误的情况下读取/写入少于请求。所以通常你不应该在 QFile::write 附近骑自行车自己。

但是,另一方面,根据线程“QFile::write(const QByteArray&) 不写入所有数据?”在“兴趣”Qt 邮件列表中 May 2018 , 存在以下情况 QFile::write写的比请求的少,并且围绕 QFile::write 循环很有用。至少它们存在于 2018 年 5 月,Alexander Golks said he couldn't reproduce the problem after upgrading to Qt 5.6.4 (但我不知道到底是什么被修复/改变了,因为在那之前的很多年里,自行车都是QFSFileEnginePrivate::writeFdFh)。但令我震惊的不是QFile::write。没有外部循环在一个较旧的 Qt 版本中是不够的(谁知道,也许这是一个已修复的 Qt 错误或必须通过其他方式解决的硬件/驱动程序问题)但是直接接受的邮件列表成员参与 Qt 开发(例如 Thiago Macieira)的立场是 a-la “不要指望 QFile::write写一切,骑自行车”。

结论。我不知道该说些什么。我的猜测是:

  • Qt 的精神是“QIODevice::write只有在出现错误的情况下才会写入少于请求的内容,因此不需要外部循环”。这就是为什么 Qt 开发人员既不提供围绕 QIODevice::write 进行外部循环的便捷方法的原因。外部循环也不围绕 QIODevice::write他们自己在更高级别的类(class)中,例如 QTextStream , QDataStream .
  • 但是他们不敢保证这种方法会奏效(总是对所有 QIODevice 后代)。这就是文档的字母 不提供此类保证的原因。 (它仅对 QIODevice::writeData 实现者施加义务,但对 QIODevice::write 用户不施加特权。)
  • 我个人的选择是不围绕 QFile::write 进行外部循环.

关于c++ - 使用 QFile::write 的正确方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51170486/

相关文章:

c++ - Qt-如何实现一个可读写的QSqlQueryModel?

json - 如何通过 QByteArray 以 JSON 形式存储 QPixmap?

c++ - 是否可以在 C++ 中创建指向非静态成员函数的指针?

c++ - 合并两个 vector 而不在 C++ 中对它们进行排序

c++ - 用多态成员函数替换 lambda 函数

c++ - Qt Creator 错误 : LNK1123: failure during conversion to COFF: file invalid or corrupt

c++ - Windows 上的 Qt::AA_SynthesizeMouseForUnhandledTouchEvents

c++ - 使用 Visual Studio 构建 JNI dll 时出现链接错误

c++ - 从 qjsonarray 中删除大括号并从文档中替换方括号

c++ - 有什么方法可以通过 Qt Designer 添加 QSystemTrayIcon