2010-02-08 12 views

risposta

10

Generalmente quando si cerca un sacco di cose per qualcosa, non si può essere sicuri della loro mancanza di esistenza a meno che non si sia cercato tutti i posti possibili che avrebbe potuto essere. Quando si cerca qualcosa (nella maggior parte dei tipi di collezioni) il caso peggiore è quando l'oggetto non esiste nella collezione.

Non ho un benchmarking File.Exists in particolare ma dubito fortemente che ci sia una differenza davvero notevole in quei casi, a meno che non lo facciate migliaia di volte. Come sei arrivato a questa conclusione?

+0

Effettivamente - confronta a "Elenco .Conti". –

+0

Considera un file che esiste ma l'utente non ha accesso ad esso. Il flusso non sarebbe lo stesso di se l'utente avesse? vale a dire: ottenere un puntatore al file e controllare le autorizzazioni? O forse le autorizzazioni impediscono di trovare il file per controllare le autorizzazioni e sembra una lista vuota?o la stessa cosa che stai descrivendo si verifica quando controlli le autorizzazioni? iniziando a dare un senso a me, immagino. Thx –

+0

Sì, le autorizzazioni sono ancora un'altra raccolta da cercare. Se trovi quello che stai cercando, puoi rinunciare immediatamente, mentre per concludere non riesci a trovare quello che stai cercando, dovrai verificare tutte le possibilità. –

39

File.Exists intercetta le eccezioni. Il sovraccarico di raccolta e acquisizione di un'eccezione può contribuire a prestazioni scadenti.

File.Exists funziona così:

controllare per vedere se il file esiste, tenta di aprire il file ... se viene generata un'eccezione il file non esiste.

Questo processo è più lento dell'apertura di un file e non viene generata alcuna eccezione (ovvero quando il file esiste).

+0

Grazie. L'avevo notato nella documentazione e mi chiedevo. Probabilmente influisce anche sulle prestazioni. Farei clic sulla freccia su per te ma non ho ancora la reputazione. –

+0

Anche questo è stato il mio primo pensiero. @Sarah, se è davvero un problema, potresti voler tornare a P/Invocare Win32 GetFileAttributes() (che restituisce -1 se il file non è stato trovato). – peterchen

+0

Questo è il problema di File.Exists che tenta di aprire il file. Se un altro thread tenta di accedere al file contemporaneamente (mentre il file viene aperto), diciamo che ci saranno conseguenze sfortunate! – SepehrM

28

File.Exists crea inoltre un'istanza di autorizzazione CLR prima di verificare che il file esista per il file. Un'alternativa (anche se non ho provato per le prestazioni) è PathFileExists se si sta facendo un sacco di controlli:

[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

Questo è MOLTO più veloce. Ho appena eseguito un test delle prestazioni non isolato su un codice che avevo utilizzato File.Exists. L'ho poi ri-eseguito dopo aver aggiornato la mia implementazione per utilizzare il tuo approccio sopra. Il codice originale (sullo stesso scenario di utilizzo) utilizzava il 5% del tempo di traccia dello stack. Utilizzando questo approccio, tale numero è sceso a circa lo 0,5%. Per il nostro processo che controlla ripetutamente la presenza di file, questo rappresenta un enorme miglioramento. Grazie! –

+0

È sbalorditivo quanto sia più veloce! – BradVoy

+0

Stavo facendo un po 'di tempo con i controlli File.Exists che richiedevano una quantità folle di tempo. Questa soluzione riduce l'elaborazione a una frazione del tempo. – Siewers

-4

file e tutti i suoi metodi tipicamente lavorare con handle di file di Windows.

Se si fanno un sacco di controlli, si dovrebbe usare:

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

Invece di lavorare internamente con handle di file, esamina attributi di file ed è molto più veloce. Inoltre, non controlla le eccezioni, che è una grande rallentamento .NET

+1

Sembra che "FileInfo.Exists" alla fine effettui le stesse chiamate di "File.Exists". (Usando Reflector, puoi vedere che deve eseguire 'FillAttributeInfo' e aprire' SafeFindHandle', proprio come 'File.Exists'). –

3

Ho eseguito il seguente test, e sul mio PC, almeno, i tempi sono circa la stessa:

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

i risultati sono stati in linea con il seguente (ogni corsa è leggermente diverso, ma circa la stessa):

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

ma attraverso una rete (sulla LAN a un server di un hop di distanza), ho trovato la prova di essere un po 'più lento quando i file sono effettivamente esistiti. L'ho annusato e c'era un solo pacchetto SMB in ogni direzione.

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

Questo test non è molto affidabile perché si misura anche l'output sulla console. – t3chb0t

+0

@ t3chb0t: l'output visualizzato è l'output totale. Non sono riuscito a essere molto chiaro su questo, ma il primo ciclo funzionava con i file esistenti (quindi nessun output da quel loop) e il secondo era per file che non esistevano (quindi nessun output). Quindi i tempi non includevano alcuna uscita della console. I numeri sarebbero stati molto più grandi se avessero incluso 1000 linee di output per console. –

Problemi correlati