C# 在Windows 10 IOT中安全保存文件

C# 在Windows 10 IOT中安全保存文件,c#,io,windows-10-iot-core,windowsiot,C#,Io,Windows 10 Iot Core,Windowsiot,我的团队需要一种防弹的方式在Windows10IoT上保存文件(小于100kb) 文件无法损坏,但如果由于断电等原因导致保存失败,可以释放最新版本 由于文件IO发生了显著变化(不再有File.Replace),我们不确定如何实现它 我们可以看到: var file = await folder.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists); await Windows.Storage.FileIO.WriteTex

我的团队需要一种防弹的方式在Windows10IoT上保存文件(小于100kb)

文件无法损坏,但如果由于断电等原因导致保存失败,可以释放最新版本

由于文件IO发生了显著变化(不再有File.Replace),我们不确定如何实现它

我们可以看到:

var file = await folder.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists);
await Windows.Storage.FileIO.WriteTextAsync(file, data);
是可靠的不可靠的(在停止调试或重置设备时它会反复中断。)并且我们最终会得到一个损坏的文件(满是零)和一个.tmp文件。我们可以恢复这个.tmp文件。我不确定我们的解决方案是否应该基于未记录的行为

我们想尝试的一种方法是:

var tmpfile = await folder.CreateFileAsync(fileName+".tmp",
                               CreationCollisionOption.ReplaceExisting);
await Windows.Storage.FileIO.WriteTextAsync(tmpfile, data);

var file = await folder.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists);

// can this end up with a corrupt or missing file?
await tmpfile.MoveAndReplaceAsync(file); 

总之,是否有一种安全的方法将一些文本保存到一个永远不会损坏文件的文件中?

不确定是否有最佳做法,但如果需要自己想出一些办法:

我会做一些类似于计算校验和的事情,并将其与文件一起保存

下次保存时,不要覆盖它,而是将其保存在上一次保存的旁边(应为“已知良好”),只有在验证新保存成功(连同校验和)后,才能删除上一次保存


我还假设重命名操作不会损坏文件,但我还没有研究过这篇文章是否有一个很好的解释:关于在UWP中写入文件所涉及的底层过程

强调了以下常见问题:

  • 文件部分写入
  • 应用程序在调用其中一个方法时收到异常
  • 这些操作会留下与目标文件名类似的.TMP文件
在讨论与的权衡时,不容易推断出的是,尽管创建或编辑操作更容易失败,因为它们做了很多事情,但如果重命名操作不在文件系统中物理写入位,那么它们的容错性就要高得多

您建议先创建一个临时文件,这是正确的,可能会很好地为您服务,但是使用
moveandreplaceAncy
意味着您仍然容易遇到这些已知问题,如果目标文件已经存在

UWP将在文件系统中使用事务模式,并可能创建源文件和目标文件的各种备份副本

您可以通过在调用
MoveAndReplaceAsync
之前删除原始文件来控制最后一个元素,或者您可以简单地使用
RenameAsync
如果临时文件位于同一文件夹中,则这些文件的组件较少,这将减少故障区域

@hansmbakker有这样一个答案:如何确定文件写入是否成功取决于您,但是如果您需要防弹,那么在覆盖原始文件之前隔离繁重的写入操作并进行验证是一个好主意


关于失败 我观察了很多.TMP文件,当使用
FileIO
写入的Append变体时,.TMP文件在Append之前具有原始文件的内容,但是实际的文件并不总是具有原始客户端的所有内容,有时是新旧内容的混合,有时是

根据我的经验,当对写入操作的整个调用结构是异步的并且正确地等待管道时,UWP文件写入是非常可靠的。您可以采取步骤确保在任何时间点只有一个进程尝试访问同一文件

当您尝试从同步上下文中操作文件时,我们可以开始看到您所识别的“不可靠”性质,这在从旧的同步操作转换到新的FileIO操作异步变体的代码中经常发生

确保调用write方法的代码是非阻塞的,并正确等待,这将允许您捕获可能引发的任何异常

对于我们这些传统上具有同步思维的开发人员来说,尝试使用
lock(){}
模式来确保对文件的单一访问是很常见的,但是在
lock
中您无法轻松地等待
,并且尝试这样做往往会成为UWP文件写入问题的根源

如果您的代码有一个锁定机制来确保对文件的单例访问,那么请阅读这些文章以了解不同的方法,它们虽然很旧,但是是一个很好的资源,涵盖了传统同步C#开发人员向异步和并行开发的过渡

我们遇到同步约束的其他情况是,事件、计时器或Dispose上下文首先是写入文件的触发器。这里涉及到不同的技巧,如果您认为这可能会导致您的问题,请发布另一个专门涉及该场景的问题。:)


请让我们知道我的答案是否可以接受,如果对您有帮助,请将我的答案标记为答案。我们有一个类似的问题附加到日志文件中。创建新文件似乎是可靠的,而对现有文件的写入正如您所说的“可靠不可靠”。您的新更改将保存在预期的文件名中,但如果写入失败,将创建一个包含以前内容的TMP文件。