检查文件/目录是否存在:有更好的方法吗?

40 .net c# file

我发现自己这么做只是为了确保文件名不被使用.有没有更好的办法?

Directory.Exists(name) || File.Exists(name)
Run Code Online (Sandbox Code Playgroud)

Pau*_*ulG 56

当然:)

internal static bool FileOrDirectoryExists(string name)
{
   return (Directory.Exists(name) || File.Exists(name));
}
Run Code Online (Sandbox Code Playgroud)


Leo*_*edt 34

请注意,您所使用的事实是否存在()来检查文件或目录名使用受竞争条件.

Exists()测试通过后的任何时候,例如,在代码到达创建文件的位置之前,某些东西可能已经创建了具有该名称的文件.

(我假设文件已经存在是一个特例条件).

简单地打开文件,指定适当的FileShare参数更可靠.

例:

using System;
using System.IO;

static class FileNameInUse
{
    static void Main(string[] args)
    {
        string path = args[0];
        using (var stream = File.Open(path, FileMode.CreateNew, FileAccess.Write, FileShare.None))
        {
            // Write to file
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,简单地处理失败时的IOException可能会导致更简单的代码更不容易出现竞争条件,因为现在:

  • 如果其他内容已经创建了该文件,FileMode.CreateNew则会导致IOException抛出该文件
  • 如果打开并创建成功,因为在FileShare.None关闭文件之前,没有其他进程可以访问该文件.

不幸的是,如果没有一些丑陋的P/Invoke ,就不可能检查文件当前是否正在使用,而不是抛出异常:

    bool IsFileInUse(string fileName)
    {
            IntPtr hFile = Win32.CreateFile(fileName, Win32.FILE_READ_DATA, 0, IntPtr.Zero, Win32.OPEN_EXISTING, Win32.FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);
            if (hFile.ToInt32() == Win32.INVALID_HANDLE_VALUE)
                return true;

            Win32.CloseHandle(hFile);
            return false;
    }

    class Win32
    {
        const uint FILE_READ_DATA = 0x0001;
        const uint FILE_SHARE_NONE = 0x00000000;
        const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;
        const uint OPEN_EXISTING = 3;
        const int INVALID_HANDLE_VALUE = -1;

        [DllImport("kernel32.dll", SetLastError=true)]
        internal static extern IntPtr CreateFile(string lpFileName,
                                               uint dwDesiredAccess,
                                               uint dwShareMode,
                                               IntPtr lpSecurityAttributes,
                                               uint dwCreationDisposition,
                                               uint dwFlagsAndAttributes,
                                               IntPtr hTemplateFile);

        [DllImport("kernel32.dll")]
        internal static extern bool CloseHandle(IntPtr hObject);
    }
Run Code Online (Sandbox Code Playgroud)

这种快速检查也容易出现竞争条件,除非你从中返回文件句柄,并将其传递给相关的FileStream构造函数.

  • +1 @Leon - 对于"在Exists()测试通过后的任何时候,在代码到达创建文件的位置之前,可能会创建一个具有该名称的文件,例如.." (3认同)
  • 出于某种原因,人们似乎从未因解决问题而获得认可,仅用于回答问题.+1回答应该被问到的问题. (2认同)