c# - File.WriteAllText not flushing data to disk -
i've had 3 reports of user's machines crashing while using software.. crashes not related program when restart config files program writes corrupt.
there nothing special how files being written, creating json representation , dumping disk using file.writealltext()
// save our contents disk string json = jsonconvert.serializeobject(objectinfo, formatting.indented); // write contents file.writealltext(path, json);
i've had user send me 1 of files , length looks right (~3kb) contents 0x00.
according post below file.writealltext should close file handle, flushing unwritten contents disk:
in c# code computer wait until output complete before moving on?
but, pointed out alberto in comments:
system.io.file.writealltext when completes, flush text filesystem cache, then, lazily written drive.
so presume happening here file being cleared , initialized 0x00 data not yet written when system crashes.
i thinking of maybe using sort of temp file process this:
- write new contents temp file
- delete original file
- rename temp file original
i don't think solve problem presume windows move file though io still pending.
is there way can force machine dump data disk instead of deciding when or perhaps better way update file?
update:
based on suggestions @usr, @mikez , @llya luzyanin i've created new writealltext function performs write using following logic:
- create temp file new contents using fileoptions.writethrough flag
- writes data disk (won't return until write has completed)
- file.replace copy contents of new temp file real file, making backup
with logic, if final file fails load, code check backup file , load instead
here code:
public static void writealltextwithbackup(string path, string contents) { // generate temp filename var temppath = path.gettempfilename(); // create backup name var backup = path + ".backup"; // delete existing backups if (file.exists(backup)) file.delete(backup); // bytes var data = encoding.utf8.getbytes(contents); // write data temp file using (var tempfile = file.create(temppath, 4096, fileoptions.writethrough)) tempfile.write(data, 0, data.length); // replace contents file.replace(temppath, path, backup); }
you can use filestream.flush
force data disk. write temp file , use file.replace
atomically replace target file.
i believe guaranteed work. file systems give weak guarantees. these guarantees hardly ever documented , complex.
alternatively, can use transactional ntfs if available. available .net.
fileoptions.writethrough
can replace flush
still need temp file if data can exceed single cluster in size.
Comments
Post a Comment