Ich muss überprüfen, ob das Verzeichnis auf der Festplatte leer ist. Dies bedeutet, dass es keine Ordner / Dateien enthält. Ich weiß, dass es eine einfache Methode gibt. Wir erhalten ein Array von FileSystemInfos und prüfen, ob die Anzahl der Elemente gleich Null ist. Sowas in der Art:
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();
}
Dieser Ansatz scheint in Ordnung zu sein. ABER!! Aus Sicht der Leistung ist es sehr, sehr schlecht. GetFileSystemInfos () ist eine sehr schwierige Methode. Tatsächlich werden alle Dateisystemobjekte des Ordners aufgelistet, alle ihre Eigenschaften abgerufen, Objekte erstellt, typisierte Arrays gefüllt usw. Und dies alles nur, um einfach die Länge zu überprüfen. Das ist doch blöd, oder?
Ich habe gerade einen solchen Code profiliert und festgestellt, dass ~ 250 Aufrufe einer solchen Methode in ~ 500 ms ausgeführt werden. Das ist sehr langsam und ich glaube, dass es möglich ist, es viel schneller zu machen.
Irgendwelche Vorschläge?
Antworten:
In
Directory
undDirectoryInfo
in .NET 4 gibt es eine neue Funktion , mit der sieIEnumerable
ein Array anstelle eines Arrays zurückgeben und Ergebnisse zurückgeben können, bevor sie den gesamten Verzeichnisinhalt lesen.Directory.EnumerateFileSystemEntries
MethodenüberladungenEDIT: Als ich diese Antwort wieder sehe, ist mir klar, dass dieser Code viel einfacher gemacht werden kann ...
quelle
EnumerateFileSystemEntries
oder bei der Verwendung ein Platzhaltermuster.Any(condition)
angeben (verwenden Sie die Bedingung als Lambda-Ausdruck oder als Methode, die einen Pfad als Parameter verwendet).return !items.GetEnumerator().MoveNext();
Hier ist die extra schnelle Lösung, die ich endlich implementiert habe. Hier verwende ich WinAPI und Funktionen FindFirstFile , FindNextFile . Es ermöglicht die Aufzählung aller Elemente im Ordner und stoppt direkt nach dem Erkennen des ersten Objekts im Ordner . Dieser Ansatz ist ~ 6 (!!) Mal schneller als oben beschrieben. 250 Anrufe in 36ms!
Ich hoffe, dass es in Zukunft für jemanden nützlich sein wird.
quelle
SetLastError = true
dasDllImport
for hinzufügen ,FindFirstFile
damit derMarshal.GetHRForLastWin32Error()
Aufruf ordnungsgemäß funktioniert, wie im Abschnitt "Bemerkungen" des MSDN-Dokuments für GetHRForLastWin32Error () beschrieben .Sie könnten versuchen
Directory.Exists(path)
undDirectory.GetFiles(path)
- wahrscheinlich weniger Aufwand (keine Objekte - nur Zeichenfolgen usw.).quelle
Dieser Schnelltest kam in 2 Millisekunden für den Ordner zurück, wenn er leer war und Unterordner und Dateien enthielt (5 Ordner mit jeweils 5 Dateien).
quelle
Ich benutze dies für Ordner und Dateien (weiß nicht, ob es optimal ist)
quelle
Wenn es Ihnen nichts ausmacht, reines C # zu verlassen und WinApi- Aufrufe auszuführen , sollten Sie die Funktion PathIsDirectoryEmpty () in Betracht ziehen . Laut MSDN ist die Funktion:
Das scheint eine Funktion zu sein, die genau das tut, was Sie wollen, daher ist sie wahrscheinlich gut für diese Aufgabe optimiert (obwohl ich das nicht getestet habe).
Um es von C # aus aufzurufen , sollte Ihnen die Website pinvoke.net helfen. (Leider wird diese bestimmte Funktion noch nicht beschrieben, aber Sie sollten in der Lage sein, einige Funktionen mit ähnlichen Argumenten und Rückgabetypen dort zu finden und sie als Grundlage für Ihren Aufruf zu verwenden. Wenn Sie erneut in die MSDN schauen, heißt es, dass Die zu importierende DLL ist
shlwapi.dll
)quelle
Ich weiß nichts über die Leistungsstatistik in diesem Fall, aber haben Sie versucht, die
Directory.GetFiles()
statische Methode zu verwenden?Es gibt ein String-Array zurück, das Dateinamen enthält (nicht FileInfos), und Sie können die Länge des Arrays auf die gleiche Weise wie oben überprüfen.
quelle
Ich bin mir sicher, dass die anderen Antworten schneller sind und Ihre Frage gefragt wurde, ob ein Ordner Dateien oder Ordner enthält oder nicht ... aber ich würde denken, dass die meisten Leute ein Verzeichnis als leer betrachten, wenn es keine Dateien enthält. dh es ist für mich immer noch "leer", wenn es leere Unterverzeichnisse enthält ... dies passt möglicherweise nicht für Ihre Verwendung, aber möglicherweise für andere!
quelle
Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories).Any()
Sie müssen in jedem Fall auf die Festplatte gehen, um diese Informationen zu erhalten, und dies allein übertrumpft jede Objekterstellung und Array-Füllung.
quelle
Mir ist keine Methode bekannt, mit der Sie kurz und bündig feststellen können, ob ein bestimmter Ordner andere Ordner oder Dateien enthält. Dabei wird Folgendes verwendet:
Dies sollte die Leistung verbessern, da beide Methoden nur ein Array von Zeichenfolgen mit den Namen der Dateien / Verzeichnisse und nicht die gesamten FileSystemInfo-Objekte zurückgeben.
quelle
Vielen Dank an alle für die Antworten. Ich habe versucht, die Methoden Directory.GetFiles () und Directory.GetDirectories () zu verwenden. Gute Nachrichten! Die Leistung hat sich ~ zweimal verbessert! 229 Anrufe in 221 ms. Ich hoffe aber auch, dass es möglich ist, die Aufzählung aller Elemente im Ordner zu vermeiden. Stimmen Sie zu, dass immer noch der unnötige Job ausgeführt wird. Glaubst du nicht?
Nach allen Untersuchungen bin ich zu dem Schluss gekommen, dass unter reinem .NET eine weitere Optimierung unmöglich ist. Ich werde mit der FindFirstFile- Funktion von WinAPI spielen . Hoffe es wird helfen.
quelle
Möglicherweise möchten Sie einige Zeit überprüfen, ob Dateien in Unterverzeichnissen vorhanden sind, und diese leeren Unterverzeichnisse ignorieren. In diesem Fall können Sie die folgende Methode verwenden:
quelle
Leicht und einfach:
quelle
Basierend auf Brad Parks Code:
quelle
Mein Code ist erstaunlich, es hat nur 00: 00: 00.0007143 weniger als eine Millisekunde mit 34 Dateien im Ordner gedauert
quelle
Hier ist etwas, das Ihnen dabei helfen könnte. Ich habe es in zwei Iterationen geschafft.
quelle
Da Sie sowieso mit einem DirectoryInfo-Objekt arbeiten werden, würde ich eine Erweiterung verwenden
quelle
Benutze das. Es ist einfach.
quelle