【问题标题】:Atomically check if a file exists and open it以原子方式检查文件是否存在并打开它
【发布时间】:2015-09-28 12:35:33
【问题描述】:

我仅在文件存在时才尝试打开FileStream,否则执行其他操作(不创建它,因此FileMode.OpenOrCreate 不适用)。

但是,在创建FileStream 之前简单地检查File.Exists 不会阻止竞争条件,因为可以在FileStream 有机会创建之前删除文件,在这种情况下会抛出FileNotFoundException。

有没有办法“本地”实现这一点,而无需使用以下 try catch 包装器:

/// <returns>false if the file does not exists, true otherwise.</returns>
public static bool TryOpenFileStreamIfExists(string filePath, FileAccess fileAccess, FileShare fileShare, out FileStream fs, FileOptions fileOptions = FileOptions.None) {
    try {
        if (!File.Exists(filePath)) {
            fs = null;
            return false;
        }
        fs = new FileStream(filePath, FileMode.Open, fileAccess, fileShare, short.MaxValue, fileOptions);
        return true;
    }
    catch (FileNotFoundException) {
        fs = null;
        return false;
    }
}

【问题讨论】:

  • 在这种情况下 try/catch 包装器有什么问题?
  • 这似乎是一个合适的解决方案。 File.Exist 调用将处理大多数情况,而 catch 将处理异常情况。

标签: c# io filesystems race-condition


【解决方案1】:

您可以使用 P/Invoke 调用 Windows API 的 CreateFile() 函数来打开文件。如果文件无法打开,这将返回一个空句柄(尽管您必须调用GetLastError() 来确定为什么文件无法打开)。

确保为CreateFile() 使用返回SafeHandle 的P/Invoke 声明,例如:

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern SafeFileHandle CreateFile
(
    string lpFileName,
    [MarshalAs(UnmanagedType.U4)] FileAccess dwDesiredAccess,
    [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode,
    IntPtr lpSecurityAttributes,
    [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition,
    [MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes,
    IntPtr hTemplateFile
);

如果你这样做了,那么你可以将句柄传递给接受SafeHandle 的the overload of the FileStream() 构造函数。

这与您将要获得的“原生”差不多......

但是,我建议您只捕获异常。

【讨论】:

    猜你喜欢
    • 2012-04-11
    • 2013-08-08
    • 2022-09-23
    • 2021-08-11
    • 2014-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-05
    相关资源
    最近更新 更多