Avoid crashes when locking a file?

Comment Resolution:
Application error caused by another problem

I read / write the file in 2 different applications, when the file is read or written, it will always be blocked by application A or B, and both of them use FileShare.None .

My problem is that even wrapping the reader around try / catch still causes the application to crash using an IOException on the line in use (does not happen with the author).

I also did catch as catch (IOException ... , which I believe has no meaning, moreover, makes it more readable.

What is the correct way to ignore when a file is locked and keep trying until the file is available?

 while (true) { try { using (FileStream stream = new FileStream("test_file.dat", FileMode.Open, FileAccess.Read, FileShare.None)) { using (TextReader reader = new StreamReader(stream)) { // bla bla bla does not matter } } } catch { // bla bla bla does not matter again } Thread.Sleep(500); } 

Record

 private bool WriteData(string data) { try { using (FileStream stream = new FileStream("test_file.dat", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) { stream.SetLength(0); using (TextWriter writer = new StreamWriter(stream)) { writer.Write(data); } } return true; } catch { return false; } } 

Please note that I do not transfer the sharing rights (both the writer and the reader) to FileShare.None ) to anyone when the file is used for any process that it reads or writes, so I will handle the exception until the file is available which does not work.

+4
source share
6 answers

Here is the code we use for this purpose.

 /// <summary> /// Executes the specified action. If the action results in a file sharing violation exception, the action will be /// repeatedly retried after a short delay (which increases after every failed attempt). /// </summary> /// <param name="action">The action to be attempted and possibly retried.</param> /// <param name="maximum">Maximum amount of time to keep retrying for. When expired, any sharing violation /// exception will propagate to the caller of this method. Use null to retry indefinitely.</param> /// <param name="onSharingVio">Action to execute when a sharing violation does occur (is called before the waiting).</param> public static void WaitSharingVio(Action action, TimeSpan? maximum = null, Action onSharingVio = null) { WaitSharingVio<bool>(() => { action(); return true; }, maximum, onSharingVio); } /// <summary> /// Executes the specified function. If the function results in a file sharing violation exception, the function will be /// repeatedly retried after a short delay (which increases after every failed attempt). /// </summary> /// <param name="func">The function to be attempted and possibly retried.</param> /// <param name="maximum">Maximum amount of time to keep retrying for. When expired, any sharing violation /// exception will propagate to the caller of this method. Use null to retry indefinitely.</param> /// <param name="onSharingVio">Action to execute when a sharing violation does occur (is called before the waiting).</param> public static T WaitSharingVio<T>(Func<T> func, TimeSpan? maximum = null, Action onSharingVio = null) { var started = DateTime.UtcNow; int sleep = 279; while (true) { try { return func(); } catch (IOException ex) { int hResult = 0; try { hResult = (int) ex.GetType().GetProperty("HResult", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(ex, null); } catch { } if (hResult != -2147024864) // 0x80070020 ERROR_SHARING_VIOLATION throw; if (onSharingVio != null) onSharingVio(); } if (maximum != null) { int leftMs = (int) (maximum.Value - (DateTime.UtcNow - started)).TotalMilliseconds; if (sleep > leftMs) { Thread.Sleep(leftMs); return func(); // or throw the sharing vio exception } } Thread.Sleep(sleep); sleep = Math.Min((sleep * 3) >> 1, 10000); } } 

Usage example:

 Utilities.WaitSharingVio( action: () => { using (var f = File.Open(file, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) { // ... blah, process the file } }, onSharingVio: () => { Console.WriteLine("Sharing violation. Trying again soon..."); } ); 
+5
source

I did this once, using the information from Is there a global read / write lock? .

I assume that the result is somewhat similar to ReaderWriterLockSlim , which works when several processes, not threads, access the resource.

+2
source

You can use the mutex object to protect a shared resource from being accessed simultaneously by multiple threads or processes.

+1
source

You can check the file lock by writing a function as shown below:

 protected bool IsFileLocked(FileInfo file) { FileStream stream = null; try { stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None); } catch (IOException) { //the file is unavailable because it is: //still being written to //or being processed by another thread //or does not exist (has already been processed) return true; } finally { if (stream != null) stream.Close(); } //file is not locked return false; } 
+1
source

The answer from Timwi helped us a lot (albeit in a different context), but I found that the flag โ€œBindingFlags.Publicโ€ also needs to be added if you want to get HResult from all IOExceptions:

 public static int GetHresult(this IOException ex) { return (int)ex.GetType().GetProperty("HResult", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).GetValue(ex, null); } 
0
source

use read and write lock
correct catch syntax for

 catch(Exception e) 


 while (true) { try { using (FileStream stream = new FileStream("test_file.dat", FileMode.Open, FileAccess.Read, FileShare.None)) { using (TextReader reader = new StreamReader(stream)) { // bla bla bla does not matter } } } catch(Exception e) { // bla bla bla does not matter again } Thread.Sleep(500); } 
-1
source

Source: https://habr.com/ru/post/1439635/


All Articles