QDataStream 读取和写入的字节数比 QFile::length() 报告的要多
Posted
技术标签:
【中文标题】QDataStream 读取和写入的字节数比 QFile::length() 报告的要多【英文标题】:QDataStream reads and writes more bytes than QFile::length() reports to have 【发布时间】:2020-06-23 00:54:49 【问题描述】:我有一个实用程序可以将文件从一个位置复制到另一个位置。
我遇到的问题是,当使用QDataStream 读取 X 字节并写入它时,正在读取/写入的字节数超过了文件的字节数。我发现很多文件都会出现这个问题。
我正在使用QDataStream::readRawData() 和QDataStream::writeRawData() 来方便读取/写入文件,如下所示
QDataStream in(&sourceFile);
QDataStream out(&newFile);
// Read/Write byte containers
qint64 fileBytesRead = 0;
quint64 fileBytesWritten = 0;
qint64 bytesWrittenNow = 0;
quint8* buffer = new quint8[bufSize];
while ((fileBytesRead = in.readRawData((char*)buffer, bufSize)) != 0)
// Check if we have a read/write mismatch
if (fileBytesRead == -1)
printCritical(TAG, QString("Mismatch read/write: [R:%1/W:%2], total file write/max [W:%3/M:%4]. File may be corrupted, skipping...").arg(QString::number(fileBytesRead), QString::number(bytesWrittenNow), QString::number(fileBytesWritten), QString::number(storageFile.size)));
// close source file handle
sourceFile.close();
// Close file handle
newFile.close();
return BackupResult::IOError;
// Write buffer to file stream
bytesWrittenNow = out.writeRawData((const char*)buffer, fileBytesRead);
// Check if we have a read/write mismatch
if (bytesWrittenNow == -1)
printCritical(TAG, QString("Mismatch read/write: [R:%1/W:%2], total file write/max [W:%3/M:%4]. File may be corrupted, skipping...").arg(QString::number(fileBytesRead), QString::number(bytesWrittenNow), QString::number(fileBytesWritten), QString::number(storageFile.size)));
// close source file handle
sourceFile.close();
// Close file handle
newFile.close();
return BackupResult::IOError;
// Add current buffer size to written bytes
fileBytesWritten += bytesWrittenNow;
if(fileBytesWritten > storageFile.size)
qWarning() << "Extra bytes read/written exceeding file length"; <================= this line is hit every now and then
//...
这个问题并不一致,但时不时会发生,我不知道为什么。有人对可能的原因有想法吗?
【问题讨论】:
没有回答您的问题,但是...如果可以使用c++17
,为什么不直接使用QFile::copy
甚至std::filesystem::copy_file
?
【参考方案1】:
函数QDataStream::writeRawData() 的名称听起来很适合编写二进制数据。不幸的是,这只是故事的一半。
文件的打开模式在某些条件下也是相关的——例如如果QFile
在Windows 上用QIODevice::Text 打开:
QIODevice::Text
读取时,行尾终止符被转换为'\n'。写入时,行尾终止符被转换为本地编码,例如 Win32 的 '\r\n'。
我准备了一个MCVE 来证明:
// Qt header:
#include <QtCore>
void write(const QString &fileName, const char *data, size_t size, QIODevice::OpenMode mode)
qDebug() << "Open file" << fileName;
QFile qFile(fileName);
qFile.open(mode | QIODevice::WriteOnly);
QDataStream out(&qFile);
const int ret = out.writeRawData(data, size);
qDebug() << ret << "bytes written.";
// main application
int main(int argc, char **argv)
const char data[] =
'\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
'\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f'
;
const size_t size = sizeof data / sizeof *data;
write("data.txt", data, size, 0);
write("test.txt", data, size, QIODevice::Text);
在 Windows 10 上的 VS2017 中构建和测试:
Open file "data.txt"
16 bytes written.
Open file "test.txt"
16 bytes written.
在cygwin 的帮助下检查结果:
$ ls -l *.txt
-rwxrwx---+ 1 scheff Domänen-Benutzer 427 Jun 23 08:24 CMakeLists.txt
-rwxrwx---+ 1 scheff Domänen-Benutzer 16 Jun 23 08:37 data.txt
-rwxrwx---+ 1 scheff Domänen-Benutzer 17 Jun 23 08:37 test.txt
$
data.txt
有 16 个字节,但 test.txt
有 17 个字节。糟糕!
$ hexdump -C data.txt
00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |................|
00000010
$ hexdump -C test.txt
00000000 00 01 02 03 04 05 06 07 08 09 0d 0a 0b 0c 0d 0e |................|
00000010 0f |.|
00000011
$
显然,底层的 Windows 文件函数将\n
“纠正”为\r\n
– 09 0a 0b
变为09 0d 0a 0b
。因此,会出现一个额外的字节,该字节不是最初写入的数据的一部分。
当QFile
被打开以供阅读并涉及QIODevice::Text
时,可能会发生类似的效果。
【讨论】:
以上是关于QDataStream 读取和写入的字节数比 QFile::length() 报告的要多的主要内容,如果未能解决你的问题,请参考以下文章
如何在 PySide 和 Python 3.X 中将字节写入 QDataStream?