在繁忙的环境中可靠的文件保存(File.Replace)

mat*_*vei 25 .net c# windows filesystems

我正在研究定期需要将数据保存到磁盘的服务器软件.我需要确保旧文件被覆盖,并且在意外情况下文件不会被破坏(例如,仅部分覆盖).

我采用了以下模式:

string tempFileName = Path.GetTempFileName();
// ...write out the data to temporary file...
MoveOrReplaceFile(tempFileName, fileName);
Run Code Online (Sandbox Code Playgroud)

... 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

只要服务器具有对文件的独占访问权限,这就可以正常工作.但是,File.Replace似乎对外部文件访问非常敏感.每当我的软件在具有防病毒或实时备份系统的系统上运行时,随机的File.Replace错误就会弹出:

System.IO.IOException:无法删除要替换的文件.

以下是我已消除的一些可能原因:

  • 未发布的文件句柄:using()确保尽快释放所有文件句柄.
  • 线程问题:lock()保护对每个文件的所有访问.
  • 不同的磁盘卷:File.Replace()在跨磁盘卷使用时失败.我的方法已经检查了这一点,然后回退到File.Copy().

以下是我遇到的一些建议,以及为什么我不想使用它们:

  • 卷影复制服务:只有在有问题的第三方软件(备份和防病毒监视器等)也使用VSS时才会起作用.使用VSS需要大量的P/Invoke,并且具有特定于平台的问题.
  • 锁定文件:在C#中,锁定文件需要保持FileStream打开.它会保留第三方软件,但1)我仍然无法使用File.Replace替换文件,2)就像我上面提到的,我宁愿先写一个临时文件,以免意外腐败.

我很感激任何关于让FileRplace每次都工作的输入,或者更一般地说,可靠地保存/覆盖磁盘上的文件.

Han*_*ant 26

真的想使用第三个参数,即备份文件名.这允许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);
}
Run Code Online (Sandbox Code Playgroud)

  • 这不仅仅是将问题转移到一个级别吗?如果无法删除备份文件会怎样? (2认同)
  • 除了拥有额外的.bak文件之外,没有任何东西可以在下次删除.关键是主要操作不会失败. (2认同)
  • 对简单复制此代码的人的警告。根据“File.Delete(..)”的文档,如果备份文件不存在,它将失败,因此需要检查。 (2认同)
  • 从MSDN文章引用:"如果要删除的文件不存在,则不会抛出任何异常." (2认同)