【问题标题】:File.Replace doesn't work on shared driver?File.Replace 不适用于共享驱动程序?
【发布时间】:2019-11-27 12:18:40
【问题描述】:

以下代码在文件位于本地时有效。

var tmp = @"c:\dir\tmp.txt";
var target = @"c:\dir\target.txt";
var backup = @"c:\dir\backup10.txt";
File.Replace(tmp, target, backup);

但是,如果文件位于共享驱动器上,则会出现“拒绝访问路径”的异常。

// m:\Shared is mapped to a shared folder. And it has permissions on the folder.
var tmp = @"m:\Shared\tmp.txt";
var target = @"m:\Shared\target.txt";
var backup = @"m:\Shared\backup10.txt";
File.Replace(tmp, target, backup); // Error!

File.Replace 文档没有提到共享目录?

【问题讨论】:

  • 嗯,你怎么把之前的问题删了?无论如何,我想知道是不是因为它是一个映射的网络驱动器,并且因为File.Replace维护了安全属性等,也许这在网络驱动器上是不允许的?
  • 如果将ignoreMetadataErrors: true 传递给Replace() 方法会发生什么?
  • @PeterDuniho,传参后也不例外
  • 出于好奇,您能否在网络路径 m:\Shared 上使用 Windows 资源管理器执行相同的操作?
  • @MattU/@MickyD,这个问题已经被peter的cmets解决了。

标签: c#


【解决方案1】:

这是否适用于网络共享取决于共享。但是,看看 .NET 调用的底层本机 Win32 API ReplaceFile() function 会很有启发意义。

需要特别注意的是正确处理调用中指定的每个文件所需的访问权限。例如:

lpReplacementFileName

将替换 lpReplacedFileName 文件的文件的名称。

该函数尝试使用 SYNCHRONIZEGENERIC_READGENERIC_WRITEDELETEDELETE 打开此文件strong>WRITE_DAC 访问权限,以便它可以保留所有属性和 ACL。如果失败,该函数会尝试使用 SYNCHRONIZEGENERIC_READDELETEWRITE_DAC 访问权限打开文件权利。未指定共享模式。

任何这些权利都可能存在问题,具体取决于份额。但就您而言,我相信您遇到了 WRITE_DAC 访问权限。

正如您在上面的评论中确认的那样,当您通过 ignoreMetadataErrors: true 时,调用成功。这意味着当调用底层的ReplaceFile()函数时,传递了REPLACEFILE_IGNORE_MERGE_ERRORS标志(实际调用见微软源代码站点:https://referencesource.microsoft.com/#mscorlib/system/io/file.cs,d4b8da02b41f19a4),导致涉及@的错误987654329@ 被忽略。

由于我们无权访问您的共享,因此无法确定。但我会在甜甜圈上投入资金,在你的情况下,你没有共享的 WRITE_DAC 访问权限,因此调用失败。

只要不介意 ACL 和其他文件属性不被复制,答案就是将ignoreMetadataErrors: true 传递给方法。

如果您确实介意那些不被复制的东西,那么您应该感谢异常,它会提醒您您尝试执行的操作不受支持,并且您需要更正您的配置共享,使其按您的意愿工作(请注意,如果共享托管在不支持 Windows 样式 ACL 的文件系统上,则可能无法使其工作)。

【讨论】:

  • 如果另一个应用程序正在读取目标文件,File.Replace() 会做什么?它会等待阅读吗?还是在阅读时更改文件?
  • “如果另一个应用程序正在读取目标文件,File.Replace() 会做什么?” -- 这将取决于其他应用程序使用哪些文件共享选项.您可以阅读ReplaceFile() 文档,了解它使用了哪些访问和共享选项。只要这些不与其他应用程序冲突,调用就会成功。但如果他们这样做 - 例如另一个应用程序没有在目标文件上使用FILE_SHARE_READ——那么调用就会失败。
  • 请注意,在某种程度上,您可能不想关注这些特定类型的冲突。在处理任何类型的 I/O 时,包括文件 I/O,异常是不争的事实。您的代码需要能够优雅地对异常做出反应,在它们发生时捕获并处理它们。通常由用户来解决实际问题。
  • 我想避免的一种情况。例如,当使用两次重命名时,target => backup,然后是 tmp -> target。在两次重命名期间,其他应用程序可能找不到目标文件。 File.Replace 会阻止它发生吗?
  • “File.Replace 会阻止它发生吗?” -- 我不知道。这对我来说似乎是一个全新的问题。注意思想,File.Replace() 的全部意义在于提供原子操作。你有一个比赛,这意味着它不确定另一个应用程序可能会打开文件的哪个版本。但我认为它很可能总是会打开文件的 some 版本。否则,整个 ReplaceFile() 函数对我来说似乎坏了。
猜你喜欢
  • 1970-01-01
  • 2011-05-11
  • 2018-04-24
  • 1970-01-01
  • 1970-01-01
  • 2019-08-03
  • 1970-01-01
  • 1970-01-01
  • 2021-08-30
相关资源
最近更新 更多