Wait for the file to be freed by the process.

How to wait for a file to become free so that ss.Save() can overwrite it with a new one. If I run this twice close (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; } 
+22
c # file-io winforms ioexception
Sep 10 '09 at 18:02
source share
7 answers

A function like this will do this:

  public static bool IsFileReady(String sFilename) { // 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(sFilename, FileMode.Open, FileAccess.Read, FileShare.None)) { if (inputStream.Length > 0) { return true; } else { return false; } } } catch (Exception) { return false; } } 

Paste it into the while loop and you have something that will be locked until the file is available

+44
Sep 10 '09 at 18:12
source share

If you check access before writing to a file, another process may access again before you can write. Therefore, I would suggest one of the following two:

  • Wrap what you want to do in the repeat area, which will not hide any other errors.
  • Create a wrapper method that waits until you can get the stream and use this stream.

receiving 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 as follows:

 using (var stream = GetWriteStream("path")) { using (var writer = new StreamWriter(stream)) writer.Write("test"); } 

repeat area

 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), content));

+8
May 11 '16 at 6:26
source share
 bool isLocked = true; while (isLocked) try { System.IO.File.Move(filename, filename2); isLocked = false; } catch { } System.IO.File.Move(filename2, filename); 
+3
Sep 10 '09 at 18:08
source share

There is no function that allows you to wait for a specific location of the descriptor / file system to be writable. Unfortunately, all you can do is poll the pen for writing.

+2
Sep 10 '09 at 18:06
source share

You can let the system wait until the process is closed.

Just as simple:

Process.Start("the path of your text file or exe").WaitForExit();

+2
Oct 05 '15 at 8:23
source share

Here is a solution that may be excessive for some users. I created a new static class that has an event that fires only when the file finishes copying.

The user registers the files that they would like to view by calling FileAccessWatcher.RegisterWaitForFileAccess(filePath) . If the file is not yet viewed, a new task is launched, which re-checks the file to see if it can be opened. Each time it checks, it also reads the file size. If the file size does not increase at a given time (5 minutes in my example), the cycle ends.

When the loop exits from a file accessible or from a timeout, the FileFinishedCopying event is FileFinishedCopying .

 public class FileAccessWatcher { // this list keeps track of files being watched private static ConcurrentDictionary<string, FileAccessWatcher> watchedFiles = new ConcurrentDictionary<string, FileAccessWatcher>(); public static void RegisterWaitForFileAccess(string filePath) { // if the file is already being watched, don't do anything if (watchedFiles.ContainsKey(filePath)) { return; } // otherwise, start watching it FileAccessWatcher accessWatcher = new FileAccessWatcher(filePath); watchedFiles[filePath] = accessWatcher; accessWatcher.StartWatching(); } /// <summary> /// Event triggered when the file is finished copying or when the file size has not increased in the last 5 minutes. /// </summary> public static event FileSystemEventHandler FileFinishedCopying; private static readonly TimeSpan MaximumIdleTime = TimeSpan.FromMinutes(5); private readonly FileInfo file; private long lastFileSize = 0; private DateTime timeOfLastFileSizeIncrease = DateTime.Now; private FileAccessWatcher(string filePath) { this.file = new FileInfo(filePath); } private Task StartWatching() { return Task.Factory.StartNew(this.RunLoop); } private void RunLoop() { while (this.IsFileLocked()) { long currentFileSize = this.GetFileSize(); if (currentFileSize > this.lastFileSize) { this.lastFileSize = currentFileSize; this.timeOfLastFileSizeIncrease = DateTime.Now; } // if the file size has not increased for a pre-defined time limit, cancel if (DateTime.Now - this.timeOfLastFileSizeIncrease > MaximumIdleTime) { break; } } this.RemoveFromWatchedFiles(); this.RaiseFileFinishedCopyingEvent(); } private void RemoveFromWatchedFiles() { FileAccessWatcher accessWatcher; watchedFiles.TryRemove(this.file.FullName, out accessWatcher); } private void RaiseFileFinishedCopyingEvent() { FileFinishedCopying?.Invoke(this, new FileSystemEventArgs(WatcherChangeTypes.Changed, this.file.FullName, this.file.Name)); } private long GetFileSize() { return this.file.Length; } private bool IsFileLocked() { try { using (this.file.Open(FileMode.Open)) { } } catch (IOException e) { var errorCode = Marshal.GetHRForException(e) & ((1 << 16) - 1); return errorCode == 32 || errorCode == 33; } return false; } } 

Usage example:

 // register the event FileAccessWatcher.FileFinishedCopying += FileAccessWatcher_FileFinishedCopying; // start monitoring the file (put this inside the OnChanged event handler of the FileSystemWatcher FileAccessWatcher.RegisterWaitForFileAccess(fileSystemEventArgs.FullPath); 

Process FileFinishedCopyingEvent file:

 private void FileAccessWatcher_FileFinishedCopying(object sender, FileSystemEventArgs e) { Console.WriteLine("File finished copying: " + e.FullPath); } 
+2
Oct 14 '16 at 4:35
source share

You can use the lock statement with the Dummy variable, and it seems to work fine.

Check here .

0
May 28 '17 at 10:08 a.m.
source share



All Articles