How do I wait for the file to be free so that ss.Save()
can overwrite it with a new one? If I run this twice close together(ish), I get a generic GDI+
error.
///<summary> /// Grabs a screen shot of the App and saves it to the C drive in jpg ///</summary> private static String GetDesktopImage(DevExpress.XtraEditors.XtraForm whichForm) { Rectangle bounds = whichForm.Bounds; // This solves my problem but creates a clutter issue // var timeStamp = DateTime.Now.ToString("ddd-MMM-dd-yyyy-hh-mm-ss"); // var fileName = "C:\\HelpMe" + timeStamp + ".jpg"; var fileName = "C:\\HelpMe.jpg"; File.Create(fileName); using (Bitmap ss = new Bitmap(bounds.Width, bounds.Height)) using (Graphics g = Graphics.FromImage(ss)) { g.CopyFromScreen(whichForm.Location, Point.Empty, bounds.Size); ss.Save(fileName, ImageFormat.Jpeg); } return fileName; }
If you check access before writing to the file some other process might snatch the access again before you manage to do your write. Therefor I would suggest one of the following two:
getting a stream
private FileStream GetWriteStream(string path, int timeoutMs) { var time = Stopwatch.StartNew(); while (time.ElapsedMilliseconds < timeoutMs) { try { return new FileStream(path, FileMode.Create, FileAccess.Write); } catch (IOException e) { // access error if (e.HResult != -2147024864) throw; } } throw new TimeoutException($"Failed to get a write handle to {path} within {timeoutMs}ms."); }
then use it like this:
using (var stream = GetWriteStream("path")) { using (var writer = new StreamWriter(stream)) writer.Write("test"); }
retry scope
private void WithRetry(Action action, int timeoutMs = 1000) { var time = Stopwatch.StartNew(); while(time.ElapsedMilliseconds < timeoutMs) { try { action(); return; } catch (IOException e) { // access error if (e.HResult != -2147024864) throw; } } throw new Exception("Failed perform action within allotted time."); }
and then use WithRetry(() => File.WriteAllText(Path.Combine(_directory, name), contents));
A function like this will do it:
public static bool IsFileReady(string filename) { // If the file can be opened for exclusive access it means that the file // is no longer locked by another process. try { using (FileStream inputStream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.None)) return inputStream.Length > 0; } catch (Exception) { return false; } }
Stick it in a while
loop and you have something which will block until the file is accessible:
public static void WaitForFile(string filename) { //This will lock the execution until the file is ready //TODO: Add some logic to make it async and cancelable while (!IsFileReady(filename)) { } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With