Parlando con il mio collega Fabioriguardo un progetto che sta seguendo, abbiamo convenuto che sarebbe utile avere la possibilità di sapere se un file è in utilizzo da qualche processo, per permetterci di attendere che venga liberato per essere elaborato dalla nostra procedura.
Girando un pò in internet ho visto che la soluzione più gettonata è quella di mettere un bel(battuta) try{…}cath(IOException){…} e nel catch valutare il dafarsi.
Questa soluzione non mi piace principalmente per 3 motivi:
1)Usare le eccezioni per una cosa che potrebbe non essere una “eccezione” non mi sembra corretto, io sono della fazione che tratta le eccezioni come un evento inaspettato e non un modo per fare logiche di business.
2)Sollevare e gestire una eccezione è dispendioso e se c’è la possibilità preferisco evitare di pagare questo prezzo.
3)Spesso il tipo di eccezione non individua precisamente il problema dove sta, a meno che non facciamo del “parsing” su qualche proprietà di essa, in quanto un tipo di eccezione può raggruppare più tipo di errori.
Detto questo(attenzione ho detto non MI piace, tutto è opinabile, avete il mio contatto se volete che ne parliamo approfonditamente), ho deciso di cercare un modo più “pulito” per risolvere questo problema e sono arrivato alla soluzione che consiste nello scrivere un extension method alla classe System.IO.FileInfo che controlla attraverso l’utilizzo di una API(nello specifico CreateFile)del sistema operativo se il file in questione è utilizzato da qualche altro processo.
Il pattern di utilizzo è abbastanza semplice:
//Creo il FileInfo
var fileInfo = new FileInfo(path);
//Controllo se il file è usato
Console.WriteLine("File usato: {0}", fileInfo.IsUsingByAnotherProcess());
per poterlo utilizzare dobbiamo avere visibilità sulla classe FileInfoExtension che contiene l’extension method.
Questo metodo tuttavia non è perfetto, o meglio, soffre di “race condition” ovvero se tra la chiamata IsUsingByAnotherProcess() e l’apertura del file(per processarlo) qualcuno si mette in mezzo possiamo comunque prenderci una bella eccezione per file usato da un’altro processo, ma in quel caso possiamo correttamente gestire l’eccezione come meglio ci pare(quì si che non ci aspettavamo di trovarlo occupato di nuovo). Il caso più utile in cui questo metodo può essere usato è quando sappiamo che qualcuno potrebbe “usare” il file e poi tocca a noi…per esempio un upload di file e scheduled task che elabora il file, quì è chiaro che solo noi e l’upload possono usare il file e in ordine prevedibile. Nel caso questo non fosse il vostro caso potete gestirlo nel catch(IOException) ancora attraverso questo extension method così da essere certi che il problema sia ancora quello, riprovando succesivamente l’operazione.
Potete scaricare il codice di esempio FileInfoExtension.zip (40,61 kb)
Se qualcuno ha qualche idea migliore o qualcosa da aggiungere, prego!
------------------------
Ho mandato un feedback a microsoft sulla problematica, ma dicono che non hanno pianificato di aggiungerlo nella versione 4.0 e che qualcun altro aveva già sottolineato una mancanza in questa api, lascio il link del feedback http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=468166 , magari in una versione futura fanno qualcosa.