Esto en realidad es un poco raro, a menos que el espacio problemático haya cambiado significativamente desde la última vez que tuve que lidiar con él.
La manera más fácil es simplemente tratar de abrir el archivo, capturar el resultado IOException
, y si el archivo está bloqueado, agréguelo a una cola para revisarlo más tarde. No puede tratar de procesar cada archivo que ingrese porque hay todo tipo de casos en los que se generarán múltiples eventos para el mismo archivo, por lo que configurar un ciclo de reintento en cada evento recibido puede convertirse en un desastre, rápido. En su lugar, debe ponerlos en cola y verificar la cola a intervalos regulares.
Aquí está una plantilla de clase básica que debe ayudar con este 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 - Estoy recordando esto desde la memoria aquí, así que puede que no sea perfecta - que me haga saber si se trata de cochecillo .)
Bien, esto es lo que hice mientras esperaba. Usé un tiempo de espera y una espera de reintento, esperaba que hubiera algo más elegante, pero bueno;) (Gracias a un millón por ir al esfuerzo por una gran respuesta) – Matthew