Di recente ho dovuto utilizzare
System.IO.FileSystemWatcher per osservare una cartella ed accorgermi della
creazione di nuovi files al suo interno.
In quell'occasione ho fatto
esperienza di comportamenti anomali legati agli eventi di notifica dei
cambiamenti nei files o cartelle.
Il caso fastidioso si verifica quando un
file di grosse dimensioni arriva nella cartella: l'evento Created viene sparato
quando inizia la scrittura fisica su disco, e non alla fine. Se all'interno del
metodo legato all'evento si cerca di aprire il file si ottiene una bella
eccezione di tipo System.IOException.
using System;
using System.IO;
namespace FSWTest
{
class Program
{
static void Main(string[] args)
{
FileSystemWatcher fsw =
new FileSystemWatcher(@"C:\Temp\FSWTest");
fsw.Created += new FileSystemEventHandler(fsw_Created);
fsw.EnableRaisingEvents = true;
Console.Read();
}
static void fsw_Created(object sender, FileSystemEventArgs e)
{
Console.WriteLine("{0} {1}", e.ChangeType, e.Name);
}
}
}
I miei colleghi ed io ipotizzavamo che questo
comportamento fosse dovuto ad un baco del FileSystemWatcher del Framework 1.1,
ma nel 2.0 le cose non cambiano.
Durante la ricerca di informazioni all'interno di gruppi di discussione ho
avuto l'impressione che il baco sia localizzato a livello delle API di
Windows:
- le API FileSystemWatcher di Windows non sparano l'evento Created
nel modo giusto
- il FileSystemWatcher palleggia semplicemente gli
eventi
- l'applicativo .NET deve fare attenzione a non aprire subito i nuovi
files notificati
Una possibilità, anche se poco elegante, di gestire il comportamento anomalo dell'evento Created di
FileSystemWatcher è quella di provare ad aprire il file fino a quando non si
ottengono più eccezioni.
//Questa è la mia classe wrapper di System.IO.FileSystemWatcher
internal class FileSystemWatcherWrapper
{
FileSystemWatcher fileSystemWatcher = null;
public FileSystemWatcherWrapper()
{
this.fileSystemWatcher = new FileSystemWatcher();
this.fileSystemWatcher.Created +=
new FileSystemEventHandler(fileSystemWatcher_Created);
}
public string Path
{
get { return this.fileSystemWatcher.Path; }
set { this.fileSystemWatcher.Path = value; }
}
public string Filter
{
get { return this.fileSystemWatcher.Filter; }
set { this.fileSystemWatcher.Filter = value; }
}
public bool EnableRaisingEvents
{
get { return this.fileSystemWatcher.EnableRaisingEvents; }
set { this.fileSystemWatcher.EnableRaisingEvents = value; }
}
//Mio evento Created
public event FileSystemEventHandler Created;
private void fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
{
//Se nessuno si è agganciato da fuori non faccio nulla.
if (null == this.Created)
return;
if (TryOpenFile(e.FullPath))
this.Created(sender, e);
}
private bool TryOpenFile(string fullPath)
{
bool opened = false;
//Se con 10 tentativi non riesco ad aprire il file me ne vado a casa.
int milliseconds = 0;
for (byte attempt = 0; attempt < 10; attempt++)
{
try
{
milliseconds += 1000;
System.Threading.Thread.Sleep(milliseconds);
//Provo ad aprire il file
StreamReader sr = new StreamReader(fullPath);
//Se sono qui significa che non sono nel catch e l'apertura
//è andata bene -> quindi rilascio il file
sr.Dispose();
opened = true;
break;
}
catch (Exception ex)
{
//...
}
}
return opened;
}
}
Mitch
powered by IMHO 1.3