Как быстро проверить, пуста ли папка (.NET)?

Если у вас есть строка, которую вы считали из файла, вы можете просто заменить \n на <br>, что является разрывом строки в html, выполнив:

my_string.replace('\n', '<br>')
129
задан Noam M 5 March 2017 в 07:53
поделиться

11 ответов

Вот очень быстрое решение, которое я наконец-то реализовал. Здесь я использую WinAPI и функции FindFirstFile , FindNextFile . Это позволяет избежать перечисления всех элементов в папке и останавливается сразу после обнаружения первого объекта в папке . Этот подход в ~ 6 (!!) раз быстрее, чем описано выше. 250 звонков за 36 мс!

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();
}

Надеюсь, в будущем это кому-нибудь пригодится.

30
ответ дан 24 November 2019 в 00:26
поделиться

Мой код удивителен, он просто занял 00: 00: 00.0007143 менее чем за миллисекунду с 34 файлом в папке

   System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
    sw.Start();

     bool IsEmptyDirectory = (Directory.GetFiles("d:\\pdf").Length == 0);

     sw.Stop();
     Console.WriteLine(sw.Elapsed);
-1
ответ дан 24 November 2019 в 00:26
поделиться

Спасибо всем за ответы. Я пытался использовать методы Directory.GetFiles () и Directory.GetDirectories () . Хорошие новости! Производительность улучшилась в два раза! 229 звонков за 221мс. Но также я надеюсь, что можно избежать перечисления всех элементов в папке. Согласитесь, что все еще выполняется ненужная работа. Вам так не кажется?

После всех исследований я пришел к выводу, что под чистым .NET дальнейшая оптимизация невозможна. Я собираюсь поиграть с функцией WinAPI FindFirstFile . Надеюсь, это поможет.

2
ответ дан 24 November 2019 в 00:26
поделиться

Мне неизвестен метод, который кратко скажет вам, содержит ли данная папка какие-либо другие папки или файлы, однако использование:

Directory.GetFiles(path);
&
Directory.GetDirectories(path);

должно повысить производительность, поскольку оба этих метода будут возвращать только массив строк с именами файлов / каталогов, а не целые объекты FileSystemInfo.

3
ответ дан 24 November 2019 в 00:26
поделиться

Я не знаю о статистике производительности на этом, но вы пробовали использовать каталог . GetFiles () статический метод?

Возвращает строковый массив, содержащий имена файлов (не FileInfos), и вы можете проверить длину массива так же, как описано выше.

7
ответ дан 24 November 2019 в 00:26
поделиться
private static void test()
{
    System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
    sw.Start();

    string [] dirs = System.IO.Directory.GetDirectories("C:\\Test\\");
    string[] files = System.IO.Directory.GetFiles("C:\\Test\\");

    if (dirs.Length == 0 && files.Length == 0)
        Console.WriteLine("Empty");
    else
        Console.WriteLine("Not Empty");

    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds);
}

Этот быстрый тест вернулся за 2 миллисекунды для папки, когда она пуста и содержит подпапки и файлы (5 папок с 5 файлы в каждом)

18
ответ дан 24 November 2019 в 00:26
поделиться

Вы можете попробовать Directory.Exists (путь) и Directory.GetFiles (путь ) - вероятно, меньше накладных расходов (без объектов - только строки и т. Д.).

19
ответ дан 24 November 2019 в 00:26
поделиться

Вам придется в любом случае использовать жесткий диск для получения этой информации, и это само по себе превзойдет создание любого объекта и заполнение массива.

3
ответ дан 24 November 2019 в 00:26
поделиться

Если вы не против оставив чистый C # и перейдя к вызовам WinApi , тогда вы можете рассмотреть функцию PathIsDirectoryEmpty () . Согласно MSDN, функция:

возвращает ИСТИНА, если pszPath - пустой каталог. Возвращает FALSE, если pszPath не является каталогом или содержит хотя бы один файл, отличный от "." или "..".

Похоже, это функция, которая делает именно то, что вы хотите, поэтому она, вероятно, хорошо оптимизирована для этой задачи (хотя я еще не сказал, Я тестировал это).

Чтобы вызвать его из C #, вам должен помочь сайт pinvoke.net . (К сожалению, он еще не описывает эту конкретную функцию, но вы сможете найти там некоторые функции с аналогичными аргументами и типом возвращаемого значения и использовать их в качестве основы для своего вызова. Если вы снова посмотрите в MSDN, там говорится, что DLL для импорта - shlwapi.dll )

8
ответ дан 24 November 2019 в 00:26
поделиться

В Directory и DirectoryInfo в .NET 4 появилась новая функция, которая позволяет возвращать IEnumerable вместо массива и начинает возвращать результаты до чтения всего содержимого каталога.

См. Здесь и там

public bool IsDirectoryEmpty(string path)
{
    IEnumerable<string> items = Directory.EnumerateFileSystemEntries(path);
    using (IEnumerator<string> en = items.GetEnumerator())
    {
        return !en.MoveNext();
    }
}

РЕДАКТИРОВАТЬ: снова увидев этот ответ, я понимаю, что этот код можно сделать намного проще ...

public bool IsDirectoryEmpty(string path)
{
    return !Directory.EnumerateFileSystemEntries(path).Any();
}
266
ответ дан 24 November 2019 в 00:26
поделиться

Вам также следует завернуть тест в блок try/catch, чтобы удостовериться, что вы правильно работаете с DirectoryNotFoundException. Это классическое состояние гонки в случае, если папка будет удалена сразу после того, как вы проверили, существует ли она.

.
0
ответ дан 24 November 2019 в 00:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: