2010-02-08 9 views

Antwort

10

Im Allgemeinen, wenn Sie eine Menge Sachen für etwas suchen, können Sie nicht über ihre Existenzlosigkeit sicher sein, es sei denn, Sie haben alle möglichen Orte gesucht, die es gewesen sein könnte. Bei der Suche nach etwas (in den meisten Arten von Sammlungen) ist der schlimmste Fall, wenn das Objekt nicht in der Sammlung vorhanden ist.

Ich habe nicht speziell File.Exists Benchmarks, aber ich bezweifle stark, dass es einen wirklich spürbaren Unterschied in diesen Fällen gibt, es sei denn, Sie tun es Tausende von Malen. Wie sind Sie zu dieser Schlussfolgerung gelangt?

+0

In der Tat - im Vergleich zu 'Liste .Contains'. –

+0

Betrachten Sie eine Datei, die existiert, aber der Benutzer hat keinen Zugriff darauf. Wäre der Fluss nicht der gleiche wie wenn der Benutzer hätte? zB: Holen Sie einen Zeiger auf die Datei und prüfen Sie die Berechtigungen? Oder verhindern die Berechtigungen möglicherweise das Auffinden der Datei, um Berechtigungen zu überprüfen, und erscheinen als leere Liste?oder das gleiche, was Sie beschreiben, tritt beim Überprüfen von Berechtigungen auf? Ich denke, dass es ein bisschen Sinn macht. Thx –

+0

Ja, Berechtigungen sind eine weitere Sammlung, nach der gesucht werden soll. Wenn Sie finden, was Sie suchen, können Sie sofort aufgeben, während Sie zu dem Schluss kommen, dass Sie nicht finden können, was Sie suchen, Sie müssen alle Möglichkeiten auschecken. –

39

File.Exists ist Abfangen von Ausnahmen. Der Aufwand für das Auslösen und Erfassen einer Ausnahme kann zu einer schlechten Leistung beitragen.

File.Exists funktioniert wie folgt:

Um zu überprüfen, ob die Datei vorhanden ist, wird versucht, die Datei zu öffnen ... wenn eine Ausnahme die Datei ausgelöst wird, ist nicht vorhanden.

Dieser Prozess ist langsamer als das Öffnen einer Datei und es wird keine Ausnahme ausgelöst (wenn die Datei vorhanden ist).

+0

Danke. Ich hatte das in der Dokumentation bemerkt und mich gewundert. Es beeinflusst wahrscheinlich auch die Leistung. Ich würde auf den Pfeil nach oben klicken, aber ich habe nicht den Ruf, wie es scheint. –

+0

Das war auch mein erster Gedanke. @Sarah, wenn es wirklich ein Problem ist, möchten Sie möglicherweise auf P/Invoking Win32 GetFileAttributes() zurückgreifen (die -1 zurückgibt, wenn die Datei nicht gefunden wird). – peterchen

+0

Das ist das Problem von File.Exists versucht, die Datei zu öffnen. Wenn ein anderer Thread versucht, gleichzeitig auf die Datei zuzugreifen (während die Datei geöffnet wird), sagen wir einfach, dass es unglückliche Konsequenzen geben wird! – SepehrM

28

File.Exists instanziiert auch die CLR-Berechtigung, bevor überprüft wird, ob die Datei für die Datei vorhanden ist. Eine Alternative (obwohl ich nicht für die Leistung versucht haben) ist PathFileExists wenn Sie eine Menge von Schecks tun:

[DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Auto)] 
private extern static bool PathFileExists(StringBuilder path); 

void Exists() 
{ 
    // A StringBuilder is required for interops calls that use strings 
    StringBuilder builder = new StringBuilder(); 
    builder.Append(@"C:\test.txt"); 
    bool exists = PathFileExists(builder); 
} 
+4

Das ist viel schneller. Ich habe gerade einen nicht isolierten Leistungstest mit Code ausgeführt, der File.Exists verwendet. Ich habe es dann erneut ausgeführt, nachdem ich meine Implementierung aktualisiert habe, um Ihren Ansatz oben zu verwenden. Der ursprüngliche Code (im selben Verwendungsszenario) benötigte 5% der Stapelverfolgungszeit. Bei diesem Ansatz fiel diese Zahl auf etwa 0,5%. Für unseren Prozess, der wiederholt nach Dateiexzessen sucht, ist dies eine enorme Verbesserung. Vielen Dank! –

+0

Es ist erstaunlich, wie viel schneller das ist! – BradVoy

+0

Ich habe tausende von File.Exists checks gemacht, die unglaublich viel Zeit in Anspruch nahmen. Diese Lösung reduziert die Verarbeitung auf einen Bruchteil der Zeit. – Siewers

-4

Datei und alle ihre Methoden arbeiten in der Regel mit Windows Datei-Handles.

Wenn Sie eine Menge von Schecks tun, sollten Sie verwenden:

FileInfo fiInfo = new FileInfo(@"c:\donotexists"); 
if (fiInfo.Exists) 
    return true; 

Anstatt intern mit Datei-Handles arbeiten, ist es bei Dateiattribute aussieht und ist viel schneller. Außerdem überprüft es nicht für Ausnahmen, die eine große Verlangsamung in .NET ist

+1

Es sieht aus wie 'FileInfo.Exists' letztlich die gleichen Aufrufe wie' File.Exists'. (Mit Reflector können Sie sehen, dass es 'FillAttributeInfo' ausführen und ein' SafeFindHandle' öffnen muss, genau wie 'File.Exists'). –

3

ich den folgenden Test lief, und auf meinem PC zumindest sind die Zeiten, in etwa gleich:

static void TestExists() 
    { 
    Stopwatch sw = Stopwatch.StartNew(); 

    for (int i = 0; i < 1000; i++) 
     { 
     if (!File.Exists(@"c:\tmp\tmp" + i.ToString() + ".tmp")) 
      Console.WriteLine("File does not exist"); 
     } 
    Console.WriteLine("Total for exists: " + sw.Elapsed); 

    sw = Stopwatch.StartNew(); 
    for (int i = 0; i < 1000; i++) 
     { 
     if (File.Exists(@"c:\tmp\tmp_" + i.ToString() + ".tmp")) 
      Console.WriteLine("File exists"); 
     } 
    Console.WriteLine("Total for not exists: " + sw.Elapsed); 
    } 

die Ergebnisse entlang der Linien des folgenden waren (jeder Lauf ist etwas anders, aber etwa gleich):

Total for exists: 00:00:00.0717181 
Total for not exists: 00:00:00.0824266 

aber über ein Netzwerk (auf dem LAN zu einem Server einen Sprung entfernt), ich den Test gefunden werden ein bisschen langsamer, wenn die Dateien tatsächlich existierten. Ich schnüffelte daran und es gab nur ein SMB-Paket in jeder Richtung.

Total for exists: 00:00:02.4028708 
Total for not exists: 00:00:00.6910531 
+1

Dieser Test ist nicht sehr zuverlässig, da Sie auch die Ausgabe an die Konsole messen. – t3chb0t

+0

@ t3chb0t: Die angezeigte Ausgabe ist die Gesamtausgabe. Ich war nicht ganz klar darüber, aber die erste Schleife lief mit vorhandenen Dateien (also keine Ausgabe von dieser Schleife) und die zweite war für Dateien, die nicht existierten (also keine Ausgabe). Das Timing beinhaltete also keine Konsolenausgabe. Die Zahlen wären viel größer gewesen, wenn sie 1000 Zeilen Konsolenausgabe enthalten hätten. –

Verwandte Themen