QDataStream 读取和写入的字节数比 QFile::length() 报告要多

QDataStream reads and writes more bytes than QFile::length() reports to have

本文关键字:length 报告 QFile 读取 字节数 QDataStream      更新时间:2023-10-16

我有一个实用程序,应该将文件从一个位置复制到另一个位置。

我遇到的问题是,当使用 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
}
//...

这个问题并不一致,但它时不时地发生,我不知道为什么。有人对可能的原因有想法吗?

函数 QDataStream::writeRawData(( 的名称听起来非常适合写入二进制数据。不幸的是,这只是故事的一半。

文件的打开模式在某些条件下也是相关的 - 例如,如果使用QIODevice::Text在Windows上打开QFile

QIO网站::文本

读取时,行尾终止符将转换为""。写入时,行尾终止符将转换为本地编码,例如 Win32 的"\r"。

我准备了一个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"更正"为rn-09 0a 0b变得09 0d 0a 0b。因此,会出现一个额外的字节,它不是最初写入数据的一部分。

当打开QFile进行阅读时,可能会发生类似的效果,并涉及QIODevice::Text