2009-07-20 9 views
12

Sto monitorando una cartella per i nuovi file e ho bisogno di elaborarli. Il problema è che occasionalmente l'apertura dei file fallisce, perché il sistema non ha finito di copiarlo.Come verificare se un file è stato copiato completamente in .NET

Qual è il modo corretto di verificare se il file ha finito di copiare?

Chiarimento: Non ho autorizzazioni di scrittura per la cartella/i file e non posso controllare il processo di copia (è l'utente).

+0

Buona domanda! Quando ho avuto questo problema, ho appena aggiunto System.Threading.Thread.Sleep (1000), ma vorrei * love * per ottenere una soluzione migliore (è solo così zoppo ...) – Treb

+0

Hai accesso in lettura al file originale, che viene copiato? –

risposta

11

Penso che l'unico modo sicuro per farlo consiste nel tentare di aprire il file esclusivamente e di rilevare un'eccezione specifica.Io di solito odio usare le eccezioni per la logica normale applicazione, ma ho paura per questo scenario non c'è altro modo (almeno io non ho ancora trovato uno):

public bool FileIsDone(string path) 
{ 
    try 
    { 
    using (File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None)) 
    { 
    } 
    } 
    catch(UnauthorizedAccessException) 
    { 
    return false; 
    } 

    return true; 
} 
0

un approccio che prendo sempre è quello di creare un file alla fine della mia copia/trasferimento denominato "token.txt" senza contenuto. L'idea è che questo file verrà creato proprio alla fine dell'operazione di trasferimento, così puoi monitorare questa creazione di file e quando questo file viene creato, inizi a lavorare con i tuoi file. Non dimenticare di cancellare questo file di token sempre quando inizi ad elaborare i tuoi file.

+1

Ma se l'account utente non ha il diritto di eliminare file nel server, questo approccio non sarebbe utile. – rahul

+2

Non pensare che l'extropy sia in attesa di un processo di copia a cui lui stesso ha il controllo. Quindi non ci sarebbero file di token, giusto? – peSHIr

+1

Penso che non si possa dire se ha o meno accesso/controllo senza un processo senza ulteriori dettagli. È come un brainstorming in cui tutti danno input. –

0

Si dovrebbe coprire anche i casi come: il file è in uso da un altro programma, file è stato eliminato (copia non è riuscito), ecc ..

Utilizzare un trattamento per coprire tutti i casi importanti che potrebbero verificarsi un'eccezione estesa.

2

Non sono sicuro del "modo corretto", ma è possibile utilizzare lo strumento di monitoraggio (FileSystemWatcher presumo) per riempire una coda interna che si utilizza per l'elaborazione ritardata. O meglio ancora: basta usare una coda per posizionare i file in cui l'open fallisce, quindi puoi riprovarli più tardi.

1

Se si utilizza FileSystemWatcher non penso che ci sia una soluzione robusta a questo problema. Un approccio sarebbe provare/riprendere/riprovare più tardi.

0

Dipende, un ciclo di tentativi è probabilmente il migliore che si possa fare, se non si ha il controllo sul processo di copia.

Se si ha il controllo:

  • Se la cartella è locale, si potrebbe richiedere che la persone che scrivono cose in esso bloccare il file per l'accesso esclusivo, e rilasciare solo la serratura quando sono fatto (che Penso che sia l'impostazione predefinita per File.Copy). Sul lato .Net si potrebbe avere un semplice ciclo di tentativi, con un periodo di raffreddamento.
    • In alternativa è possibile scrivere il file in una cartella temporanea e solo dopo averlo scritto spostarlo nella directory di destinazione. Questo riduce la finestra in cui possono accadere cose cattive (ma non lo elimina)
  • Se la cartella è una condivisione SMB, c'è una possibilità che lo LockFile non funzioni nemmeno (alcune implementazioni di Linux). In tal caso l'approccio comune è di avere una sorta di file di blocco, che viene eliminato una volta che la persona che crea il file è stata eseguita. Il problema con un approccio basato su un file di lock è che se ti dimentichi di eliminarlo puoi essere nei guai.
  • In seguito a queste complicazioni, suggerirei di ricevere i dati tramite un servizio WCF o un servizio Web potrebbe essere vantaggioso perché si dispone di un controllo molto migliore.
0

Infatti, al fine di evitare condizioni di gara, i l'unica soluzione sicura è riprovare.

Se si fa qualcosa di simile:

while (file is locked) 
    no-op() 
process file() 

Si rischia un altro processo saltando tra la guardia mentre e la dichiarazione di file di processo. Indipendentemente dal modo in cui la tua "attesa di disponibilità dei file" è implementata, a meno che tu non possa garantire che il post-sblocco tu sia il primo processo per accedervi, potresti non essere il primo utente.

Questo è più probabile che potrebbe sembrare a prima vista, in particolare se più persone stanno guardando il file, e in particolare se stanno usando qualcosa come il watcher del file system. Naturalmente, non è ancora molto probabile ...

0

I file sono grandi?

Forse potresti provare a calcolare il checksum md5 sul file?

Se si inserisce l'hash MD5 nel nome file, è possibile recuperarlo e provare a ricalcolare il checksum sul file. Quando md5 è una corrispondenza, si può presumere che il file sia finito.

byte[] md5Hash = null; 
MD5 md5 = new MD5CryptoServiceProvider(); 
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) 
    md5Hash = md5.ComputeHash(fs); 

StringBuilder hex = new StringBuilder(); 
foreach (byte b in md5Hash) 
    hex.Append(b.ToString("x2")); 
0

Ecco un ciclo vb.net che utilizzo. Attende 2 secondi tra ogni controllo.

Dim donotcopy As Boolean = True 
While donotcopy = True 
    Dim myFile As New FileInfo("Filetocopy") 
    Dim sizeInBytes As Long = myFile.Length 
    Thread.Sleep(2000) 
    Dim myFile2 As New FileInfo("Filetocopy") 
    Dim sizeInBytes2 As Long = myFile2.Length 
    If sizeInBytes2 = sizeInBytes Then donotcopy = False 
End While 
Problemi correlati