File.WriteAllText不冲水的数据到磁盘 [英] File.WriteAllText not flushing data to disk

查看:565
本文介绍了File.WriteAllText不冲水的数据到磁盘的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有3份报告现在用户的机器在使用我的软件..的崩溃是不相关的我的计划,但他们重新启动时的配置文件我写的程序都是腐败的崩溃。



有什么特别的文件如何被写入,简单地创建一个JSON表示,并使用File.WriteAllText()



<$ p转储到磁盘$ p> //我们的内容保存到磁盘
JSON字符串= JsonConvert.SerializeObject(objectInfo,Formatting.Indented);

//写的内容
File.WriteAllText(路径,JSON);



我有一个用户给我发的一个文件,长度看上去只有权利(〜3KB ),但内容都为0x00



根据以下File.WriteAllText后应关闭文件句柄,冲洗任何不成文的内容复制到磁盘:



在我的C#代码执行计算机等到输出移动之前完成?



但是,正如阿尔贝托指出在评论:




System.IO.File.WriteAllText完成对时,将刷新所有文字
文件系统缓存,然后,它会懒洋洋地写入驱动器。




所以,我相信这里发生了什么是文件被清除并初始化为0x00但数据尚未写入系统崩溃时



我想也许使用某种形式的临时文件,所以这个过程会是这样的:




  1. 编写新内容的临时文件

  2. 删除原始文件

  3. 临时文件重命名为原始



我不认为因为我相信Windows将只是移动的文件,即使将解决这个问题在IO仍悬而未决。



有没有什么办法可以强制机器转储数据到磁盘上,而不是在决定什么时候做或者也许是的更好的方式来更新文件



更新:



基于我创建了使用以下逻辑执行写一个新的WriteAllText功能@usr,@mikez和@llya luzyanin建议:




  1. 创建一个临时文件,使用FileOptions.WriteThrough标志

  2. <李新内容>将数据写入磁盘(不会返回,直到写入完成)
  3. File.Replace复制新的临时文件的真实文件的内容,制作备份



通过该逻辑,如果最终文件加载失败,我的代码为备份文件并加载,而不是



下面是代码的检查:

 公共静态无效WriteAllTextWithBackup(路径字符串,字符串的内容)
{
//生成一个临时文件名
VAR TEMPPATH =路径。 GetTempFileName();

//创建备份名称
VAR备份=路径+的.backup

//删除任何现有备份
如果(File.Exists(备份))
File.Delete(备份);

//获取字节
VAR数据= Encoding.UTF8.GetBytes(内容);

//使用将数据写入一个临时文件
(VAR TEMPFILE = File.Create(TEMPPATH,4096,FileOptions.WriteThrough))
tempFile.Write(数据,0 ,data.Length);

//更换内容
File.Replace(TEMPPATH,路径,备份);
}


解决方案

您可以使用 FileStream.Flush 来的数据强制到磁盘。写一个临时文件,并使用 File.Replace 来代替原子目标文件。



我相信这是有保障上班。文件系统使弱的保证。这些担保几乎没有记载,他们是复杂的。



另外,你可以使用事务性NTFS(如果可用)。它可用于.NET。



FileOptions.WriteThrough 可替代刷新但你仍然需要临时文件,如果你的数据大小超过单个集群。


I've had 3 reports now of user's machines crashing while using my software.. the crashes are not related to my program but when they restart the config files my program writes are all corrupt.

There is nothing special to how the files are being written, simply creating a Json representation and dumping 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've had a user send me one of the files and the length looks about right (~3kb) but the contents are all 0x00.

According to the post below File.WriteAllText should close the file handle, flushing any unwritten contents to the disk:

In my C# code does the computer wait until output is complete before moving on?

BUT, as pointed out by Alberto in the comments:

System.IO.File.WriteAllText when completes, will flush all the text to the filesystem cache, then, it will be lazily written to the drive.

So I presume what is happening here is that the file is being cleared and initialized with 0x00 but the data is not yet written when the system crashes.

I was thinking of maybe using some sort of temp file so the process would be like this:

  1. Write new contents to temp file
  2. Delete original file
  3. Rename temp file to original

I don't think that will solve the problem as I presume Windows will just move the file even though the IO is still pending.

Is there any way I can force the machine to dump that data to disk instead of it deciding when to do it or perhaps a better way to update a file?

UPDATE:

Based on suggestions by @usr, @mikez and @llya luzyanin I've created a new WriteAllText function that performs the write using the following logic:

  1. Create a temp file with the new contents using the FileOptions.WriteThrough flag
  2. Writes the data to disk (won't return until the write has completed)
  3. File.Replace to copy the contents of the new temp file to the real file, making a backup

With that logic, if the final file fails to load, my code an check for a backup file and load that 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);
}

解决方案

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

I believe this is guaranteed to work. File systems give weak guarantees. These guarantees are hardly ever 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 the temp file if your data can exceed a single cluster in size.

这篇关于File.WriteAllText不冲水的数据到磁盘的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆