QDataStream читает и записывает больше байтов, чем отчеты QFile::length(), чтобы иметь

У меня есть утилита, которая копирует файлы из одного места в другое.

У меня возникла проблема при чтении X байтов с использованием QDataStream и записи, количество прочитанных/записанных байтов превышает количество байтов в файле. Я вижу, что эта проблема возникает с рядом файлов.

Я использую 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
      }

      //...

Эта проблема непостоянна, но время от времени возникает, я понятия не имею, почему. У кого какие мысли по возможной причине?


person CybeX    schedule 23.06.2020    source источник
comment
Не отвечает на ваш вопрос, но... почему бы просто не использовать QFile::copy< /a> или даже std::filesystem::copy_file, если вы можете использовать c++17?   -  person G.M.    schedule 23.06.2020


Ответы (1)


Название функции QDataStream::writeRawData() звучит как идеальное для записи бинарных данных. К сожалению, это только половина дела.

Режим открытия файла актуален и при определенных условиях – например. если QFile открыт в Windows с помощью QIODevice ::Текст:

QIODevice::Текст

При чтении терминаторы конца строки преобразуются в '\n'. При записи терминаторы конца строки переводятся в локальную кодировку, например '\r\n' для Win32.

Я подготовил 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);
}

Создан и протестирован в VS2017 в Windows 10:

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\n09 0a 0b стало 09 0d 0a 0b. Следовательно, появляется один дополнительный байт, который не был частью первоначально записанных данных.

Подобные эффекты могут произойти, когда QFile открывается для чтения с участием QIODevice::Text.

person Scheff's Cat    schedule 23.06.2020