Muszę sprawdzić, czy katalog na dysku jest pusty. Oznacza to, że nie zawiera żadnych folderów / plików. Wiem, że jest prosta metoda. Otrzymujemy tablicę FileSystemInfo i sprawdzamy, czy liczba elementów jest równa zero. Coś w tym stylu:
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();
}
To podejście wydaje się OK. ALE!! Z punktu widzenia wydajności jest to bardzo, bardzo złe. GetFileSystemInfos () jest bardzo trudną metodą. Właściwie to wylicza wszystkie obiekty systemu plików folderu, pobiera wszystkie ich właściwości, tworzy obiekty, wypełnia wpisaną tablicę itp. A wszystko po to, by po prostu sprawdzić Długość. To głupie, prawda?
Właśnie sprofilowałem taki kod i ustaliłem, że ~ 250 wywołań takiej metody jest wykonywanych w ~ 500 ms. Jest to bardzo powolne i uważam, że można to zrobić znacznie szybciej.
Jakieś sugestie?
Odpowiedzi:
Jest to nowa funkcja
Directory
iDirectoryInfo
.NET 4, który pozwala im zwracaćIEnumerable
zamiast tablicy, i zacząć zwracania wyników przed przeczytaniem całej zawartości katalogu.Directory.EnumerateFileSystemEntries
przeciążenia metodEDYCJA: widząc tę odpowiedź ponownie, zdaję sobie sprawę, że ten kod można uczynić znacznie prostszym ...
źródło
EnumerateFileSystemEntries
lub użyć.Any(condition)
(określić warunek jako wyrażenie lambda lub jako metodę, która przyjmuje ścieżkę jako parametr).return !items.GetEnumerator().MoveNext();
Oto bardzo szybkie rozwiązanie, które w końcu wdrożyłem. Tutaj używam WinAPI i funkcji FindFirstFile , FindNextFile . Pozwala to uniknąć wyliczania wszystkich elementów w folderze i zatrzymuje się zaraz po wykryciu pierwszego obiektu w folderze . To podejście jest ~ 6 (!!) razy szybsze niż opisano powyżej. 250 połączeń w 36 ms!
Mam nadzieję, że w przyszłości komuś się przyda.
źródło
SetLastError = true
doDllImport
forFindFirstFile
, abyMarshal.GetHRForLastWin32Error()
wywołanie działało poprawnie, zgodnie z opisem w sekcji uwagi w dokumencie MSDN dla GetHRForLastWin32Error () .Można spróbować
Directory.Exists(path)
iDirectory.GetFiles(path)
- prawdopodobnie mniej napowietrznych (żadne przedmioty - tylko struny itp).źródło
Ten szybki test powrócił w ciągu 2 milisekund dla folderu, gdy jest pusty i zawiera podfoldery i pliki (5 folderów po 5 plików w każdym)
źródło
Używam tego do folderów i plików (nie wiem, czy to optymalne)
źródło
Jeśli nie masz nic przeciwko pozostawieniu czystego C # i przejściu do wywołań WinApi , możesz rozważyć funkcję PathIsDirectoryEmpty () . Według MSDN funkcja:
Wygląda na to, że jest to funkcja, która robi dokładnie to, co chcesz, więc prawdopodobnie jest dobrze zoptymalizowana do tego zadania (chociaż nie testowałem tego).
Aby wywołać to z C #, witryna pinvoke.net powinna ci pomóc. (Niestety, nie opisuje jeszcze tej konkretnej funkcji, ale powinieneś być w stanie znaleźć tam niektóre funkcje z podobnymi argumentami i typem zwracania i użyć ich jako podstawy do wywołania. Jeśli spojrzysz ponownie na MSDN, zobaczysz, że biblioteka DLL do zaimportowania to
shlwapi.dll
)źródło
Nie wiem o statystykach wydajności tego, ale czy próbowałeś użyć
Directory.GetFiles()
metody statycznej?Zwraca tablicę ciągów zawierającą nazwy plików (nie FileInfos) i możesz sprawdzić długość tablicy w taki sam sposób, jak powyżej.
źródło
Jestem pewien, że inne odpowiedzi są szybsze, a twoje pytanie dotyczyło tego, czy folder zawiera pliki lub foldery ... ale myślę, że przez większość czasu ludzie uznaliby katalog za pusty, gdyby nie zawierał plików. tj. nadal jest dla mnie „pusty”, jeśli zawiera puste podkatalogi ... może to nie pasować do twojego użytku, ale może do innych!
źródło
Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories).Any()
W każdym przypadku będziesz musiał udać się na dysk twardy, aby uzyskać te informacje, a samo to ma pierwszeństwo przed tworzeniem obiektów i wypełnianiem tablic.
źródło
Nie znam metody, która zwięźle powie Ci, czy dany folder zawiera inne foldery lub pliki, jednak za pomocą:
powinno zwiększyć wydajność, ponieważ obie te metody zwracają tylko tablicę ciągów z nazwami plików / katalogów, a nie całe obiekty FileSystemInfo.
źródło
Dziękuję wszystkim za odpowiedzi. Próbowałem użyć Directory.GetFiles () i Directory.GetDirectories () metod . Dobre wieści! Wydajność poprawiła się ~ dwukrotnie! 229 połączeń w 221 ms. Ale mam też nadzieję, że da się uniknąć wyliczania wszystkich pozycji w folderze. Zgadzam się, że nadal niepotrzebna praca jest wykonywana. Nie sądzisz?
Po wszystkich badaniach doszedłem do wniosku, że w czystym .NET dalsza optymalizacja jest niemożliwa. Mam zamiar bawić się funkcją WinAPI FindFirstFile . Mam nadzieję, że to pomoże.
źródło
Czasami możesz chcieć sprawdzić, czy jakieś pliki istnieją w podkatalogach i zignorować te puste podkatalogi; w takim przypadku możesz skorzystać z poniższej metody:
źródło
Łatwe i proste:
źródło
Z siedzibą w kodzie Brad Parks :
źródło
Mój kod jest niesamowity, po prostu zajęło 00: 00: 00.0007143 mniej niż milisekundę z 34 plikami w folderze
źródło
Oto coś, co może ci w tym pomóc. Udało mi się to zrobić w dwóch iteracjach.
źródło
Ponieważ i tak zamierzasz pracować z obiektem DirectoryInfo, wybrałbym rozszerzenie
źródło
Użyj tego. To proste.
źródło