如何快速检查文件夹是否为空(.NET)? [英] How to quickly check if folder is empty (.NET)?

查看:102
本文介绍了如何快速检查文件夹是否为空(.NET)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须检查磁盘上的目录是否为空.这意味着,它不包含任何文件夹/文件.我知道,有一个简单的方法.我们获取 FileSystemInfo 的数组并检查元素计数是否为零.类似的东西:

I have to check, if directory on disk is empty. It means, that it does not contain any folders/files. I know, that there is a simple method. We get array of FileSystemInfo's and check if count of elements equals to zero. Something like that:

public static bool CheckFolderEmpty(string path)
{
    if (string.IsNullOrEmpty(path))
    {
        throw new ArgumentNullException("path");
    }

    var folder = new DirectoryInfo(path);
    if (folder.Exists)
    {
        return folder.GetFileSystemInfos().Length == 0;
    }

    throw new DirectoryNotFoundException();
}

这种方法看起来不错.但!!从性能的角度来看,这是非常非常糟糕的.GetFileSystemInfos() 是一种非常困难的方法.实际上,它枚举文件夹的所有文件系统对象,获取它们的所有属性,创建对象,填充类型化数组等.所有这些只是为了简单地检查长度.这很愚蠢,不是吗?

This approach seems OK. BUT!! It is very, very bad from a perspective of performance. GetFileSystemInfos() is a very hard method. Actually, it enumerates all filesystem objects of folder, gets all their properties, creates objects, fills typed array etc. And all this just to simply check Length. That's stupid, isn't it?

我刚刚分析了此类代码并确定,此类方法的大约 250 次调用在大约 500 毫秒内执行.这很慢,我相信可以做得更快.

I just profiled such code and determined, that ~250 calls of such method are executed in ~500ms. This is very slow and I believe, that it is possible to do it much quicker.

有什么建议吗?

推荐答案

这是我最终实现的超快速解决方案.这里我使用的是 WinAPI 和函数FindFirstFileFindNextFile.它允许避免枚举文件夹中的所有项目,并且在检测到文件夹中的第一个对象后立即停止.这种方法比上述方法快约 6(!!) 倍.36 毫秒内调用 250 个!

Here is the extra fast solution, that I finally implemented. Here I am using WinAPI and functions FindFirstFile, FindNextFile. It allows to avoid enumeration of all items in Folder and stops right after detecting the first object in the Folder. This approach is ~6(!!) times faster, than described above. 250 calls in 36ms!

private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct WIN32_FIND_DATA
{
    public uint dwFileAttributes;
    public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
    public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
    public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
    public uint nFileSizeHigh;
    public uint nFileSizeLow;
    public uint dwReserved0;
    public uint dwReserved1;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
    public string cFileName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
    public string cAlternateFileName;
}

[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);

[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);

[DllImport("kernel32.dll")]
private static extern bool FindClose(IntPtr hFindFile);

public static bool CheckDirectoryEmpty_Fast(string path)
{
    if (string.IsNullOrEmpty(path))
    {
        throw new ArgumentNullException(path);
    }

    if (Directory.Exists(path))
    {
        if (path.EndsWith(Path.DirectorySeparatorChar.ToString()))
            path += "*";
        else
            path += Path.DirectorySeparatorChar + "*";

        WIN32_FIND_DATA findData;
        var findHandle = FindFirstFile(path, out findData);

        if (findHandle != INVALID_HANDLE_VALUE)
        {
            try
            {
                bool empty = true;
                do
                {
                    if (findData.cFileName != "." && findData.cFileName != "..")
                        empty = false;
                } while (empty && FindNextFile(findHandle, out findData));

                return empty;
            }
            finally
            {
                FindClose(findHandle);
            }
        }

        throw new Exception("Failed to get directory first file",
            Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()));
    }
    throw new DirectoryNotFoundException();
}

我希望它将来对某人有用.

I hope it will be useful for somebody in the future.

这篇关于如何快速检查文件夹是否为空(.NET)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆