我正在处理定期需要将数据保存到磁盘的服务器软件。 我需要确保旧文件被覆盖,并且在出现意外的情况下文件不会被损坏(例如只是部分覆盖)。
我采用了以下模式:
string tempFileName = Path.GetTempFileName(); // ...write out the data to temporary file... MoveOrReplaceFile(tempFileName, fileName);
… MoveOrReplaceFile是:
public static void MoveOrReplaceFile( string source, string destination ) { if (source == null) throw new ArgumentNullException("source"); if (destination == null) throw new ArgumentNullException("destination"); if (File.Exists(destination)) { // File.Replace does not work across volumes if (Path.GetPathRoot(Path.GetFullPath(source)) == Path.GetPathRoot(Path.GetFullPath(destination))) { File.Replace(source, destination, null, true); } else { File.Copy(source, destination, true); } } else { File.Move(source, destination); } }
只要服务器具有对文件的独占访问权,就可以很好地工作。 但是,File.Replace似乎对外部访问文件非常敏感。 任何时候我的软件运行在一个带有杀毒软件或者实时备份系统的系统上,随机的File.Replace错误就会popup:
System.IO.IOException:无法删除要replace的文件。
以下是我已经消除的一些可能的原因:
以下是我遇到的一些build议,为什么我不想使用它们:
我会感谢任何获得File.Replace每次工作,或者更一般地,可靠地保存/覆盖磁盘上的文件的任何input。
你真的想使用第三个参数,即备份文件名。 这允许Windows简单地重命名原始文件,而不必删除它。 如果任何其他进程打开文件而不删除共享,删除将失败,重命名从来不是一个问题。 您可以在Replace()调用之后自行删除它,并忽略错误。 还要在Replace()调用之前删除它,这样重命名不会失败,并且您将清除先前尝试失败的错误。 粗略地说:
string backup = destination + ".bak"; File.Delete(backup); File.Replace(source, destination, backup, true); try { File.Delete(backup); } catch { // optional: filesToDeleteLater.Add(backup); }
有几种可能的方法,这里有一些:
当然,这三种方法都有其缺点和优点
如果软件正在写入NTFS分区,请尝试使用Transactional NTFS 。 您可以将AlphFS用于.NET包装到API。 这可能是编写文件和防止损坏的最可靠的方法。