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

发布于 2024-08-28 06:46:54 字数 109 浏览 7 评论 0 原文

我发现自己经常这样做只是为了确保文件名不被使用。有更好的办法吗?

Directory.Exists(name) || File.Exists(name)

I find myself doing this a lot just to ensure the filename is not in use. Is there a better way?

Directory.Exists(name) || File.Exists(name)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

不必你懂 2024-09-04 06:46:54

当然 :)

internal static bool FileOrDirectoryExists(string name)
{
   return (Directory.Exists(name) || File.Exists(name));
}

Sure :)

internal static bool FileOrDirectoryExists(string name)
{
   return (Directory.Exists(name) || File.Exists(name));
}
走过海棠暮 2024-09-04 06:46:54

请注意,您使用 Exists() 来检查正在使用的文件或目录名称这一事实会受到竞争条件的影响。

例如,在您的 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
        }
    }
}

因此,简单地处理失败时的 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);
    }

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

Note that the fact that you are using Exists() to check for file or directory name in use is subject to race conditions.

At any point after your Exists() test has passed, something could have created a file with that name before your code reaches the point where you create a file, for example.

(I'm assuming it is an exceptional condition for the file to already exist).

It is more reliable to simply to open the file, specifying an appropriate FileShare parameter.

Example:

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
        }
    }
}

So simply handling the IOException on failure may result in simpler code less prone to race conditions, because now:

  • If something else has already created the file, FileMode.CreateNew will cause an IOException to be thrown
  • If your open and create succeeds, because of FileShare.None, no other process can access the file until you close it.

Unfortunately, it is not possible to check whether a file is currently in use, and not throw an exception, without some ugly 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);
    }

And this fast check is also prone to race conditions, unless you return the file handle from it, and pass that to the relevant FileStream constructor.

绿阴红影里的.如风往事 2024-09-04 06:46:54

我认为这是唯一的方法。我通常有一个“FileManager”类,它具有封装 I/O 方法的静态方法,包括您指定的方法,然后在所有应用程序中使用该“FileManager”作为库。

I think that's the only way. I generally have a "FileManager" class which have static methods encapsulating I/O methods including the ones you indicated and then use that "FileManager" across all the applications as a library.

未央 2024-09-04 06:46:54

您可以使用以下功能:

[DllImport("shlwapi", EntryPoint = "PathFileExists", CharSet = CharSet.Unicode)]
public static extern bool PathExists(string path);

You can use following function:

[DllImport("shlwapi", EntryPoint = "PathFileExists", CharSet = CharSet.Unicode)]
public static extern bool PathExists(string path);
百合的盛世恋 2024-09-04 06:46:54

我检查这一点的方法是使用 FileSystemInfo,这是我的代码:

FileSystemInfo info = 
  File.GetAttributes(data.Path).HasFlag(FileAttributes.Directory) ? 
    new DirectoryInfo(data.Path) : (FileSystemInfo)new FileInfo(data.Path);

return info.Exists;

My way of checking this is using the FileSystemInfo, here is my code:

FileSystemInfo info = 
  File.GetAttributes(data.Path).HasFlag(FileAttributes.Directory) ? 
    new DirectoryInfo(data.Path) : (FileSystemInfo)new FileInfo(data.Path);

return info.Exists;
霓裳挽歌倾城醉 2024-09-04 06:46:54

以下行有效(.NET8),但接受的解决方案可能具有更好的性能(如果这在这里很重要)

var pathExists = new FileInfo(path).Attributes > 0;

The following line works (.NET8), but the accepted solution might have better performance (if that matters here)

var pathExists = new FileInfo(path).Attributes > 0;
紧拥背影 2024-09-04 06:46:54

从 .NET 7 开始,可以使用 Path.Exsist

Path.Exists(name)

https://learn.microsoft.com/en-us/dotnet/api/system.io.path.exists?view=net-8.0

Since .NET 7 it's possible to use Path.Exsist

Path.Exists(name)

https://learn.microsoft.com/en-us/dotnet/api/system.io.path.exists?view=net-8.0

相守太难 2024-09-04 06:46:54

检查文件是否存在的另一种方法。

FileInfo file = new FileInfo("file.txt");

if (file.Exists)
{
    // TO DO
}

Another way to check if file exist.

FileInfo file = new FileInfo("file.txt");

if (file.Exists)
{
    // TO DO
}
梦在深巷 2024-09-04 06:46:54

检查 FileAttributes 是否 == -1 怎么样?

public static bool PathExists(this string path) {
    DirectoryInfo dirInfo = null;
    try { dirInfo = new DirectoryInfo(path.TrimEnd(Path.DirectorySeparatorChar)); }
    catch { }
    if (dirInfo == null || dirInfo.Attributes == (FileAttributes)(-1))
        return false;
    return true;
}

How about checking whether FileAttributes == -1?

public static bool PathExists(this string path) {
    DirectoryInfo dirInfo = null;
    try { dirInfo = new DirectoryInfo(path.TrimEnd(Path.DirectorySeparatorChar)); }
    catch { }
    if (dirInfo == null || dirInfo.Attributes == (FileAttributes)(-1))
        return false;
    return true;
}
沐歌 2024-09-04 06:46:54

检查目录是否存在

string root = @"C:\Temp";        
// If directory does not exist, don't even try   
if (Directory.Exists(root))  
{  
    Directory.Delete(root);  
}  

在C#中使用File.exists方法检查文件是否存在。
首先检查当前目录中是否存在该文件。

if (File.Exists("MyFile.txt")) {
   Console.WriteLine("The file exists.");
}

然后检查目录中是否存在该文件

if (File.Exists(@"D:\myfile.txt")) {
   Console.WriteLine("The file exists.");
}

Check if a directory Exists

string root = @"C:\Temp";        
// If directory does not exist, don't even try   
if (Directory.Exists(root))  
{  
    Directory.Delete(root);  
}  

Use the File.exists method in C# to check if a file exits in C# or not.
Firstly, check whether the file is present in the current directory.

if (File.Exists("MyFile.txt")) {
   Console.WriteLine("The file exists.");
}

After that check whether the file exist in a directory or not

if (File.Exists(@"D:\myfile.txt")) {
   Console.WriteLine("The file exists.");
}
清浅ˋ旧时光 2024-09-04 06:46:54
bool FileOrDirectoryExists(string path)
{
    try
    {
        File.GetAttributes(_source);
    }
    catch (FileNotFoundException)
    {
        return false;
    }
    return true;
}
bool FileOrDirectoryExists(string path)
{
    try
    {
        File.GetAttributes(_source);
    }
    catch (FileNotFoundException)
    {
        return false;
    }
    return true;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文