Использование fsync() для сохранения двоичных файлов в C или C++

Мой компьютер недавно внезапно выключился. Когда я снова включил его, я обнаружил, что некоторые из двоичных файлов, которые я написал, когда компьютер работал в последний раз, были повреждены. Я исследовал это и обнаружил, что это связано с тем, что данные, записанные с использованием fwrite, не гарантируют немедленной записи на диск. Мне сказали, что для того, чтобы сохранить свои данные без риска потерять их в случае очередного внезапного отключения электроэнергии, я должен воспользоваться функцией fsync. Но похоже, что это только для Unix/Linux, расположенное в unistd.h. Я на Windows, как мне сделать эквивалент fsync на Windows?

Я хочу защитить данные, записанные с помощью простой программы, следующим образом:

void WriteBinFile(float var1, float var2, float var3)
{
    FILE *fp;
    fopen_s(&fp, "filename.dat", "wb");
    fwrite((void*)&var1, sizeof(float), 1, fp);
    fwrite((void*)&var2, sizeof(float), 1, fp);
    fwrite((void*)&var3, sizeof(float), 1, fp);
    // fsync(fp) ??? No such function exists on Windows. Here I want a facility to write data to disk in non-volatile manner.
    fclose(fp);
}

P.S. Почему у меня нет ИБП - долгая и неинтересная история. Также я на Windows 8.1 и использую Visual Studio 2013. Также файлы, которые пострадали из-за резкого отключения питания, содержали 0s. Некоторые из них были заполнены 0, а некоторые лишь частично заполнены 0. Я не писал 0s в файл, так что это точно следствие отключения электричества


person The Vivandiere    schedule 14.09.2015    source источник
comment
Если ваши файлы были повреждены, вы должны использовать правильную файловую систему. Обычно вы должны были потерять только последние записанные данные, но без повреждения. В любом случае, «fsync» сильно замедлит работу. В общем, ИБП определенно лучше инвестировать.   -  person too honest for this site    schedule 15.09.2015
comment
@nabiachlevelii: Ерунда, это совсем другое.   -  person too honest for this site    schedule 15.09.2015
comment
Выберите язык. С это не С++!   -  person too honest for this site    schedule 15.09.2015
comment
@Olaf Файлы содержали 0, а это не то, что я им написал. Итак, я думаю, что я потерял данные, а не испортил их. Я использовал это слово повреждено, потому что я объединил их, когда писал вопрос.   -  person The Vivandiere    schedule 15.09.2015
comment
@Olaf Я отметил оба языка, потому что я открыт для предложений только для кода C ++, который решит проблему.   -  person The Vivandiere    schedule 15.09.2015
comment
Еще выберите язык. Поскольку вы должны делать это по-другому в C++, я предполагаю, что это C. Поэтому: Не выполняйте приведение к/от void *.   -  person too honest for this site    schedule 15.09.2015
comment
@Olaf код изначально C++. Выбрал язык   -  person The Vivandiere    schedule 15.09.2015
comment
Если вы используете CreateFIle и т. д., есть флаги для пропуска каждого буфера (но это становится неудобным, потому что вам всегда нужно записывать полные блоки жесткого диска и т. д. и т. д.).   -  person deviantfan    schedule 15.09.2015


Ответы (3)


Для тех, кто перестал читать после первого абзаца, есть следующие три шага.

  1. Звоните fflush(fp). Это сбросит все данные из буферов C stdio в буферы операционной системы.

  2. Используйте Как мне получить файл HANDLE из структуры fopen FILE?

  3. Затем вызовите FlushFileBuffers на РУЧКУ. Это удалит все данные из буферов ОС Windows на диск.

person Zan Lynx    schedule 14.09.2015
comment
Спасибо. Вы знаете, работает ли fflush(fp) для этого? - person The Vivandiere; 15.09.2015
comment
@FirstJens: сначала я забыл упомянуть fflush, пока не увидел его в ответе Джошуа. Это необходимо для получения данных из буфера, встроенного в функции C stdio. После этого вам понадобятся FlushFileBuffers, чтобы получить данные из буферов операционной системы. - person Zan Lynx; 15.09.2015
comment
Спасибо. Я сейчас читаю код. Он довольно плотный. - person The Vivandiere; 15.09.2015
comment
Ух ты, два минуса без единого поясняющего комментария. - person Zan Lynx; 16.09.2015
comment
fflush() не соответствует fsync(). Первая — это библиотечная функция C, которая сбрасывает буферы из приложения в ядро, а вторая — это системный вызов, который сбрасывает буферы из ядра на диск. В системах, в которых они оба есть, вам нужно будет использовать их оба для достижения цели ОП. Эквивалентом fsync() в Windows является FlushFileBuffer(). - person user207421; 01.10.2015
comment
@EJP: Кажется, ваш комментарий просто переформулировал мой ответ? - person Zan Lynx; 01.10.2015


Я могу ошибаться, но я считаю, что fflush(fp); должен помочь.

person Joshua Green    schedule 14.09.2015
comment
Хотя это и не так, это влияет только на буферизацию времени выполнения C. В Windows может быть другой уровень (у него он есть). - person deviantfan; 15.09.2015