File.WriteAllText does not clear data on disk

I had 3 reports of crashes in user machines when using my software. The crashes are not related to my program, but when they restart the configuration files, my program writes all the damaged ones.

There is nothing special about how files are written, just creating a Json view and unloading it to disk using File.WriteAllText ()

// save our contents to the disk string json = JsonConvert.SerializeObject(objectInfo, Formatting.Indented); // write the contents File.WriteAllText(path, json); 

I had a user who sent me one of the files, and the length looks something like this (~ 3kb), but the entire contents is 0x00.

According to the message below, File.WriteAllText should close the file descriptor by flushing any unwritten contents to disk:

In my C # computer code, wait for the output to complete before continuing?

BUT, as Alberto pointed out in the comments:

System.IO.File.WriteAllText, when it is complete, will clear all the text until then the file system cache will be lazily written to disk.

Therefore, I assume that what happens here is that the file is cleared and initialized with 0x00, but the data has not yet been written when the system crashes.

I thought maybe using some kind of temporary file, so the process would be like this:

  • Writing new content to temp file
  • Delete source file
  • Rename the temp file to the original

I don't think this will solve the problem, as I assume that Windows will simply move the file, even if IO is still waiting.

Is there a way to make the machine unload this data to disk instead of deciding when to do it, or perhaps the best way to update the file?

UPDATE:

Based on the suggestions of @usr, @mikez and @llya luzyanin, I created a new WriteAllText function that writes using the following logic:

  • Create a temporary file with new content using the FileOptions.WriteThrough flag
  • Writes data to disk (will not return until recording is complete)
  • File.Replace to copy the contents of the new temp file to the real file, making a backup

With this logic, if the last file does not load, my code checks the backup file and downloads it instead

Here is the code:

 public static void WriteAllTextWithBackup(string path, string contents) { // generate a temp filename var tempPath = Path.GetTempFileName(); // create the backup name var backup = path + ".backup"; // delete any existing backups if (File.Exists(backup)) File.Delete(backup); // get the bytes var data = Encoding.UTF8.GetBytes(contents); // write the data to a temp file using (var tempFile = File.Create(tempPath, 4096, FileOptions.WriteThrough)) tempFile.Write(data, 0, data.Length); // replace the contents File.Replace(tempPath, path, backup); } 
+7
c # windows io disk
source share
1 answer

You can use FileStream.Flush to force data to disk. Write to the temp file and use File.Replace to automatically replace the target file.

I believe this is guaranteed. File systems give weak guarantees. These guarantees are almost never documented, and they are complex.

Alternatively, you can use Transactional NTFS, if available. It is available for .NET.

FileOptions.WriteThrough can replace Flush , but you still need a temporary file if your data can exceed one cluster in size.

+8
source share

All Articles