1

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

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

      //...

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

4

1 回答 1

1

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

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

QIODevice::文本

读取时,行尾终止符被转换为 '\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 0b09 0d 0a 0b. 因此,出现了一个额外的字节,它不是最初写入的数据的一部分。

QFile当打开阅读时可能会发生类似的效果QIODevice::Text

于 2020-06-23T06:53:07.677 回答