问题
[Using C# and Windows as platform]
I have a camera that writes JPG files to a local folder in my PC. I want to load each file the camera drops, so I have a FileSystemWatcher that notifies me whenever a new picture is created, but the camera locks the file while it's being written, so if I try to load it just after being notified of its creation, I get an exception saying that the file is locked.
Currently, I have a while loop (with a Thread.Sleep) that retries to load the image every 0.2 seconds, but it feels a bit dirty.
Is there a more elegant way to wait until the lock has been released, so I can load the file being sure that it's no longer used??
回答1:
You will not be able to get around trial and error approach, i.e., try to open the file, catch IOException, try again. However, you can hide this ugliness in a separate class like so:
public class CustomWatcher
{
private readonly FileSystemWatcher watcher;
public event EventHandler<FileSystemEventArgs> CreatedAndReleased;
public CustomWatcher(string path)
{
watcher = new FileSystemWatcher(path, "*.jpg");
watcher.Created += OnFileCreated;
watcher.EnableRaisingEvents = true;
}
private void OnFileCreated(object sender, FileSystemEventArgs e)
{
// Running the loop on another thread. That means the event
// callback will be on the new thread. This can be omitted
// if it does not matter if you are blocking the current thread.
Task.Run(() =>
{
// Obviously some sort of timeout could be useful here.
// Test until you can open the file, then trigger the CreeatedAndReleased event.
while (!CanOpen(e.FullPath))
{
Thread.Sleep(200);
}
OnCreatedAndReleased(e);
});
}
private void OnCreatedAndReleased(FileSystemEventArgs e)
{
CreatedAndReleased?.Invoke(this, e);
}
private static bool CanOpen(string file)
{
FileStream stream = null;
try
{
stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.None);
}
catch (IOException)
{
return false;
}
finally
{
stream?.Close();
}
return true;
}
}
This "watcher" can be used like this:
var watcher = new CustomWatcher("path");
watcher.CreatedAndReleased += (o,e) =>
{
// Now, your watcher has managed to open and close the file,
// so the camera is done with it. Obviously, any other application
// is able to lock it before this code manages to open the file.
var stream = File.OpenRead(e.FullPath);
}
Disclaimer: CustomWatcher probably needs to be IDisposable and dispose of the FileSystemWatcher appropriately. The code merely shows an example of how to achieve the desired functionality.
来源:https://stackoverflow.com/questions/36205450/getting-notified-when-a-file-lock-is-released