Resolution from comments:
Application crash was caused by another issue
I am reading/writting to a file from 2 different applications, when the file is being read or written to, it will always be locked by app A or B and they both make use of FileShare.None
.
My issue is that even wrapping the reader around try/catch it still crashes the application with IOException at the using line (does not happen with the writter).
I have also made the catch as catch (IOException ...
which I believe makes no difference other then make it more readable.
What is the correct way to ignore when the 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);
}
Write
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 am not giving share rights (both writer and reader use FileShare.None
) to anyone when the file is being used for whatever process be it reading or writting so basically I am handling the exception until the file is available which is not working.
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);
}
}
Example of use:
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...");
}
);
I did this once using info from Is there a global named reader/writer lock?.
I suppose the outcome is somewhat like a ReaderWriterLockSlim
that works in the case where multiple processes, not threads, are accessing a resource.
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