Ten jest właściwie odrobiną dozy, chyba że przestrzeń problemu zmieniła się znacząco od czasu, gdy ostatnio musiałem sobie z tym poradzić.
Najprostszym sposobem jest po prostu spróbuj otworzyć plik, przechwycić wynikowy plik IOException
, a jeśli plik jest zablokowany, dodaj go do kolejki, aby później sprawdzić. Nie możesz po prostu sprobować przetwarzać każdego przychodzącego pliku, ponieważ istnieją różne rodzaje przypadków, w których generowane są różne zdarzenia dla tego samego pliku, więc ustawienie pętli ponownej próby dla każdego odebranego zdarzenia może szybko przekształcić się w katastrofę. Zamiast tego należy je umieścić w kolejce i regularnie sprawdzać kolejkę.
Oto podstawowe klasy szablon, który powinien pomóc z tym problemem:
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);
}
}
}
(Uwaga - Ja przypominając to z pamięci tutaj, więc nie może być doskonały - daj mi znać, jeśli jest wadliwy .)
Dobrze, właśnie z tym poszedłem, czekając. Użyłem limitu czasowego i ponownego oczekiwania, miałem nadzieję, że było coś bardziej eleganckiego, ale no cóż;) (Dzięki za milion wysiłku za wspaniałą odpowiedź) – Matthew