Уверете се, че всички байтове са правилно записани във файла

Възможно ли е да се провери дали всички байтове действително се записват на QFile или не? В момента това е всичко, което имам

QFile f(name);
if (f.open(QIODevice::WriteOnly)){
     f.write(bytes);
}

bytes има размер от 1 MB и има моменти, когато цялата част не е записана във файл, следователно в крайна сметка получавам повреден файл.


person BurninatorDor    schedule 07.10.2014    source източник


Отговори (5)


Това, което търсите, е контролна сума, с която можете да проверите целостта на вашите данни. Това, което искате да направите тук, е да използвате qChecksum по този начин:

QFile f(name);
if (f.open(QIODevice::ReadWrite)) {
     f.write(bytes);
}

quint16 fileCheckSum = qChecksum(bytes.data(), bytes.length());

if (f.open(QIODevice::ReadWrite)) {
    QByteArray writtenBytes = f.readAll();

    quint16 writtenBytesCheckSum = qChecksum(writtenBytes .data(), writtenBytes .length());

    if(fileCheckSum == writtenBytesCheckSum)
    {
        qDebug() << "File is valid.";
    }
    else
    {
        qDebug() << "File is corrupt.";
    }
}

Не съм компилирал кода, но трябва да работи. Ако не, ще бъда по-конкретен с пример.

person Jacob Krieg    schedule 07.10.2014
comment
Благодаря! Точно това, което търсих - person BurninatorDor; 08.10.2014
comment
Разбира се, това не гарантира, че файлът наистина е стигнал до диска, тъй като събирате контролна сума на кеша и не гарантира, че в случай, че записът е неуспешен, оригиналният файл няма да бъде унищожен. - person Kuba hasn't forgotten Monica; 09.10.2014

В Qt 5 наистина трябва да използвате QSaveFile. Той гарантира две много важни инварианти:

  1. частични/неуспешни записи не повреждат съществуващия файл,

  2. файлът се изтрива до момента, в който екземплярът QSaveFile бъде унищожен.

Тъй като това е правилен C++ клас, внедряващ RAII, не е необходимо да правите нищо специално, за да сте сигурни, че работи, освен да трябва да извикате commit(). Значението на commit() е: вие посочвате, че няма да записвате повече данни във файла. В този момент реализацията е свободна да затвори файла, да го изтрие на диска и да замени стария файл с новия.

/// When this function returns true, you can be certain that the file contains exactly "foo bar".
bool writeFooBar() {
  QSaveFile file(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
  if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
    return false;
  if (-1 == file.write("foo bar"))
    return false;
  return file.commit();
}
person Kuba hasn't forgotten Monica    schedule 08.10.2014
comment
Това работи ли на таблет с Android и има ли голяма вероятност от прекъсване на захранването? - person Muhammet Ali Asan; 21.03.2017
comment
Предполагам, че ще, това е Linux и предполагам, че Qt използва обичайната Linux C библиотека за достъп до файловата система. - person Kuba hasn't forgotten Monica; 21.03.2017

Ако се притеснявате от записването на повредени файлове, може би QSaveFile ще бъде по-добър клас за използване вместо QFile.

Както се посочва в документацията: -

QSaveFile е входно/изходно устройство за писане на текстови и двоични файлове, без загуба на съществуващи данни, ако операцията по запис е неуспешна.

person TheDarkKnight    schedule 08.10.2014

За да уверите, че всички байтове са записани правилно във файл, трябва да поддържате дайджест (контролна сума) на всички байтове, записани във файла. Сравнете резултата от резултата от текущата контролна сума с този от контролна сума, извършена над файла.

Моля, проучете SHA-1 (Secure Hash Algorithm), MD5 и „Хеш функциите“. Също така "c++ алгоритъм за цялост на данните".

person Thomas Matthews    schedule 07.10.2014
comment
Може би помага за ОП. Qt вече има някои класове за md5 и други: qt-project.org/doc/ qt-5/QCryptographicHash.html - person Kosovan; 08.10.2014
comment
Благодаря за връзката @Chernobyl. Получавам SHA1 за всеки bytes в момента. Просто не съм много запознат с процеса, за който @ThomasMatthews говори. Предполагам, че ще трябва да проуча допълнително и да се върна към него. - person BurninatorDor; 08.10.2014

QFile::flush или QFile::close трябва да предизвика запис на цялото буферирано съдържание. Важно е да проверите върнатите стойности на всички извиквания на QFile.

person James Roth    schedule 07.10.2014
comment
В моето приложение пиша няколко bytes от 1 MB всяко. Да кажем, че след добавяне на 10 MB данни, ако направя f.flush() ще знам, че определен блок е непълен? Ще мога ли обаче да разбера кой точно блок? - person BurninatorDor; 07.10.2014
comment
write, flush или close ще върне false, ако системното извикване на по-ниско ниво е неуспешно. Например, ако няма повече дисково пространство. Ако не вярвате на това, може би защото друг процес или нишка драска във вашия файл, можете да затворите файла, да го отворите само за четене и да го сравните с байтове. Ами ако файлът се повреди след този тест? В един момент трябва да се доверите на върнатите стойности. - person James Roth; 08.10.2014