How to quickly check if folder is empty (.NET)?

后端 未结 18 913
旧时难觅i
旧时难觅i 2020-12-02 08:22

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\'

18条回答
  •  慢半拍i
    慢半拍i (楼主)
    2020-12-02 08:37

    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.

提交回复
热议问题