C# File.WriteAllText未将数据刷新到磁盘
我已经收到3份报告,用户的机器在使用我的软件时崩溃。。崩溃与我的程序无关,但当它们重新启动配置文件时,我的程序写入的文件都已损坏 文件的编写方式没有什么特别之处,只需创建一个Json表示并使用File.WriteAllText()将其转储到磁盘 我让一个用户给我发送了一个文件,长度看起来差不多(~3kb),但内容都是0x00 根据下面的帖子,File.writealText应关闭文件句柄,将任何未写入的内容刷新到磁盘: 但是,正如阿尔贝托在评论中指出的那样: System.IO.File.WriteAllText完成后,将刷新所有文本到 然后,文件系统缓存将被延迟写入驱动器 因此,我假设这里发生的是,文件正在被清除并用0x00初始化,但当系统崩溃时,数据尚未写入 我在考虑使用某种临时文件,因此过程如下:C# File.WriteAllText未将数据刷新到磁盘,c#,windows,io,disk,C#,Windows,Io,Disk,我已经收到3份报告,用户的机器在使用我的软件时崩溃。。崩溃与我的程序无关,但当它们重新启动配置文件时,我的程序写入的文件都已损坏 文件的编写方式没有什么特别之处,只需创建一个Json表示并使用File.WriteAllText()将其转储到磁盘 我让一个用户给我发送了一个文件,长度看起来差不多(~3kb),但内容都是0x00 根据下面的帖子,File.writealText应关闭文件句柄,将任何未写入的内容刷新到磁盘: 但是,正如阿尔贝托在评论中指出的那样: System.IO.File.Wr
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);
}
您可以使用
FileStream.Flush
强制将数据存储到磁盘。写入临时文件并使用file.Replace
以原子方式替换目标文件
我相信这一定会奏效。文件系统提供的保证很弱。这些担保几乎没有记录在案,而且很复杂
或者,如果可用,也可以使用事务性NTFS。它可用于.NET
FileOptions.WriteThrough
可以替换Flush
,但是如果数据的大小超过一个集群,那么您仍然需要临时文件。老实说,在这种情况下,我认为您最好花点时间,确定导致系统崩溃的原因。它们只是人们机器上的随机崩溃,与我的系统无关(我认为其中一个被报告为驱动问题)。无论如何,问题是,作为软件开发人员,我的用户要求我确保我的程序在获得BSOD或其他任何情况下不会失去配置。您是否尝试使用File.Create
方法而不是File.writealText
?它有一个有用的重载-,它接受FileOptions参数,该参数可以设置为WriteThrough
-“指示系统应该通过任何中间缓存写入并直接转到磁盘。”您可以查看手动创建FileStream
,并使用FileOptions.WriteThrough
选项。问题显示了如何禁用所有缓冲,这只能通过PInvoke完成。@如果您使用WriteThrough写入1GB,我认为直观地认为数据可以部分写入。当调用返回数据时,数据是稳定的,但在此之前,可以混合使用新旧数据。这只会影响临时文件。那么,数据就是丢失了。旧数据保留下来,有意义。我想在这种情况下,丢失新数据可能比损坏的配置要好。是的,拥有旧数据的副本就可以了。。用户丢失了一些信息,但没有丢失much@miked丢失数据是一个无法解决的问题,因为在您开始写之前,机器可能会出现蓝屏。不过,崩溃一致性是可以解决的。我已经用新的写入函数更新了我的问题。。我认为逻辑是正确的?
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);
}