Използване на 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. Защо нямам UPS е дълга и безинтересна история. Освен това съм с Windows 8.1 и използвам Visual Studio 2013. Освен това файловете, които бяха засегнати поради внезапното прекъсване на захранването, съдържаха 0s. Някои от тях бяха пълни с 0s, а някои от тях бяха само частично пълни с 0s. Не съм написал 0s във файла, така че това определено е следствие от прекъсване на захранването


person The Vivandiere    schedule 14.09.2015    source източник
comment
Ако вашите файлове са повредени, трябва да използвате правилна файлова система. Обикновено трябва да сте загубили само последните записани данни, но без повреда. Или по друг начин, 'fsync' ще забави операциите масово. Като цяло, UPS определено е по-добра инвестиция.   -  person too honest for this site    schedule 15.09.2015
comment
@набиячлевэлиь: Глупости, това е нещо съвсем друго.   -  person too honest for this site    schedule 15.09.2015
comment
Изберете език. C не е C++!   -  person too honest for this site    schedule 15.09.2015
comment
@Olaf Файловете съдържаха 0s, което не е това, което им написах. Така че, предполагам, че загубих данните, вместо да се повредят. Използвах thw думата corrupted, защото смесих двете, когато написах въпроса   -  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 и т.н., има флагове за пропускане на всеки буфер (но става неудобно, защото винаги трябва да записвате пълни HDD блокове и т.н.)   -  person deviantfan    schedule 15.09.2015


Отговори (3)


За тези, които спират да четат след първия параграф, следваттристъпки.

  1. Обадете се на fflush(fp). Това ще изчисти всички данни от буферите на C stdio в буферите на операционната система.

  2. Използвайте Как да вземете файла HANDLE от структурата fopen FILE?

  3. След това извикайте FlushFileBuffers на HANDLE. Това ще изчисти всички данни от буферите на Windows OS и ще ги прехвърли на диска.

person Zan Lynx    schedule 14.09.2015
comment
Благодаря. Знаете ли дали fflush(fp) също работи за това? - person The Vivandiere; 15.09.2015
comment
@FirstJens: Забравям да спомена fflush в началото, докато не го видях в отговора на Джошуа. Това е необходимо, за да се извадят данните от буфера, вграден в stdio функциите на C. След това се нуждаете от 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 библиотека, която изхвърля буферите от приложението в ядрото: втората е системно извикване, което изчиства буферите от ядрото върху диска. На системи, които ги имат и двете, ще трябва да ги използвате и двете, за да постигнете целта на OP. Еквивалентът на Windows на fsync() е 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