Questo in realtà è un po 'un doozie, a meno che lo spazio del problema non sia cambiato in modo significativo dall'ultima volta che ho dovuto occuparmene.
Il modo più semplice è semplicemente provare ad aprire il file, catturare il risultato IOException
e, se il file è bloccato, aggiungerlo a una coda per essere controllato in seguito. Non puoi semplicemente provare a elaborare tutti i file che arrivano perché ci sono tutti i tipi di casi in cui verranno generati più eventi per lo stesso file, quindi impostare un ciclo di tentativi su ogni singolo evento ricevuto può trasformarsi in un disastro, in fretta. È necessario metterli in coda e controllare la coda a intervalli regolari.
Ecco un modello di classe di base che dovrebbe aiutare con questo problema:
public class FileMonitor : IDisposable
{
private const int PollInterval = 5000;
private FileSystemWatcher watcher;
private HashSet<string> filesToProcess = new HashSet<string>();
private Timer fileTimer; // System.Threading.Timer
public FileMonitor(string path)
{
if (path == null)
throw new ArgumentNullException("path");
watcher = new FileSystemWatcher();
watcher.Path = path;
watcher.NotifyFilter = NotifyFilters.FileName;
watcher.Created += new FileSystemEventHandler(FileCreated);
watcher.EnableRaisingEvents = true;
fileTimer = new Timer(new TimerCallback(ProcessFilesTimer),
null, PollInterval, Timeout.Infinite);
}
public void Dispose()
{
fileTimer.Dispose();
watcher.Dispose();
}
private void FileCreated(object source, FileSystemEventArgs e)
{
lock (filesToProcess)
{
filesToProcess.Add(e.FullPath);
}
}
private void ProcessFile(FileStream fs)
{
// Your code here...
}
private void ProcessFilesTimer(object state)
{
string[] currentFiles;
lock (filesToProcess)
{
currentFiles = filesToProcess.ToArray();
}
foreach (string fileName in currentFiles)
{
TryProcessFile(fileName);
}
fileTimer.Change(PollInterval, Timeout.Infinite);
}
private void TryProcessFile(string fileName)
{
FileStream fs = null;
try
{
FileInfo fi = new FileInfo(fileName);
fs = fi.OpenRead();
}
catch (IOException)
{
// Possibly log this error
return;
}
using (fs)
{
ProcessFile(fs);
}
lock (filesToProcess)
{
filesToProcess.Remove(fileName);
}
}
}
(Nota - sto Ricordando questo a memoria qui quindi potrebbe non essere perfetto - fatemi sapere se si tratta di buggy .)
Bello, questo è quello che sono andato con mentre stavo aspettando. Ho usato un time-out e una nuova attesa, speravo che ci fosse qualcosa di più elegante, ma oh, va bene;) (Grazie mille per aver cercato di ottenere una grande risposta) – Matthew