I have a multithreading application which write to the same file on a specific event .
how can i lock the file and make the thread wait until its free ?
i can't use FileStream since it will throw exception on the other threads (can't acces)
FileStream fileStream = new FileStream(file, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
is there any proper way to do this ?
You need a thread-safe filewriter to manage threads. You can use ReaderWriterLockSlim to perform it.
public class FileWriter
{
private static ReaderWriterLockSlim lock_ = new ReaderWriterLockSlim();
public void WriteData(string dataWh,string filePath)
{
lock_.EnterWriteLock();
try
{
using (var fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
byte[] dataAsByteArray = new UTF8Encoding(true).GetBytes(dataWh);
fs.Write(dataAsByteArray, 0, dataWh.Length);
}
}
finally
{
lock_.ExitWriteLock();
}
}
}
Example;
Parallel.For(0, 100, new ParallelOptions { MaxDegreeOfParallelism = 10 },i =>
{
new FileWriter().WriteData("Sample Data", Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"SampleFile.txt"));
});
Related
main(string[] args) {
string file = #"D:\123.txt";
using (FileStream f = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
f.Position = 0;
StartReadBookThread(f);
}
}
//this is a public API for user
public static Thread StartReadBookThread(Stream stream)
{
Console.WriteLine("CanSeek:" + stream.CanSeek);
var t = new Thread(() => DoReadBook(stream));
t.Start();
return t;
}
private static void DoReadBook(Stream stream)
{
Console.WriteLine("CanSeek:" + stream.CanSeek);
}
In the DoReadBook method,the stream becomes closed, CanSeek becomes false.
How to handle it if I want to read the stream in a thread
the general way is we provide a public API StartReadBookThread for user and it run in a thread .
user we always like call the parameter file stream in the suggest using(){} ... way.
so how can we read the file in a better way.
you know we just do it in a thread,sometimes it may get closed.
Your stream is disposed when StartReadBookThread returns and you hit the } in your using statement in main.
Your workflow is basically:
Buy a lawn mower (FileStream).
Ask a worker to mow the lawn (Thread).
Immediately return the lawn mower (using statement).
Expect the worker to keep on mowing the lawn with a lawn mower you no longer have (wrong expectations).
using (FileStream f = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var stream = new MemoryStream();
f.Position = 0;
f.CopyTo(stream);
StartReadBookThread(stream );
}
I'd like this code
U need to wait on thread you are returning from function StartReadBookThread
Have look at updated code snippet.
main(string[] args)
{
string file = #"D:\123.txt";
using (FileStream f = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
f.Position = 0;
var t = StartReadBookThread(f);
t.Join(); // wait on the thread
}
}
private static Thread StartReadBookThread(Stream stream)
{
Console.WriteLine("CanSeek:" + stream.CanSeek);
var t = new Thread(() => DoReadBook(stream));
t.Start();
return t;
}
What is the best way to execute file opening asynchronously even before copying begins. The exception I get is that the file is not accessible because its being used by another process.
try
{
using (var sourceStream = new FileStream(pathToDownloadedMedia, FileMode.Open, FileAccess.Read, FileShare.None, bufferSize: 4096, useAsync: true))
{
using (var destinationStream = File.Create(pathToProcessedMedia))
{
await sourceStream.CopyToAsync(destinationStream);
}
}
}
catch (Exception)
{
throw new ApplicationException();
}
I Tried an altenative as shown below but with no success. The same error prevails.
using (var sourceStream = await Task.Factory.StartNew(() => File.Open(pathToDownloadedMedia, FileMode.Open, FileAccess.Read, FileShare.None)))
{
using (var destinationStream = File.Create(pathToProcessedMedia))
{
await sourceStream.CopyToAsync(destinationStream);
}
}
No; different threads attempting to open the file at the same time will interfere with each other. You could lock a shared object to force the threads to run one at a time.
Or just use the built-in .NET tracing functionality; you can configure your app.config to write to a file.
I found the solution. Simply switching to Fileshare.ReadWrite solved the problem
using (var sourceStream = await Task.Factory.StartNew(() => File.Open(pathToDownloadedMedia, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
{
using (var destinationStream = File.Create(pathToProcessedMedia))
{
await sourceStream.CopyToAsync(destinationStream);
}
}
I modified the solution by taking away the Task being created. It works well now.
using (var sourceStream = File.Open(pathToDownloadedMedia, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (var destinationStream = File.Create(pathToProcessedMedia))
{
await sourceStream.CopyToAsync(destinationStream);
}
}
I'm using a filestream to access a file (making an md5 ComputeHash). If I attempt to rename the file during this time (which fails as the file is being accessed). So far so good, but when I then try to open the file anew after the original filestream is closed I get the info that the file is open in another process.
Code:
using (Stream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
MD5 md5 = MD5.Create();
byte[] mymd5computed = md5.ComputeHash(fileStream);
......
}
Thread.Sleep(50);
Thread a = new Thread (()=>{(FileStream sourceStream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){....} });
Like I said if while during the computation of the MD5 I try to rename the file I get the info that the file is still locked.
The lock on a file sometimes isn't released right away when you close your stream, so there are some other solutions you can use to wait until you can access the file again. One of them is explained here: http://www.codeproject.com/Tips/164428/C-FileStream-Lock-How-to-wait-for-a-file-to-get-re.
Recap:
public static void Lock(string path, Action<FileStream> action) {
var autoResetEvent = new AutoResetEvent(false);
while(true)
{
try
{
using (var file = File.Open(path,
FileMode.OpenOrCreate,
FileAccess.ReadWrite,
FileShare.Write))
{
action(file);
break;
}
}
catch (IOException)
{
var fileSystemWatcher =
new FileSystemWatcher(Path.GetDirectoryName(path))
{
EnableRaisingEvents = true
};
fileSystemWatcher.Changed +=
(o, e) =>
{
if(Path.GetFullPath(e.FullPath) == Path.GetFullPath(path))
{
autoResetEvent.Set();
}
};
autoResetEvent.WaitOne();
}
}
}
Sample use:
Lock(#"c:\file",
(f) =>
{
try
{
f.Write(buf, 0, buf.Length);
}
catch(IOException ioe)
{
// handle IOException
}
});
Hope it helps! :)
I have a windows service writes its log in a text file in a simple format.
Now, I'm going to create a small application to read the service's log and shows both the existing log and the added one as live view.
The problem is that the service locks the text file for adding the new lines and at the same time the viewer application locks the file for reading.
The Service Code:
void WriteInLog(string logFilePath, data)
{
File.AppendAllText(logFilePath,
string.Format("{0} : {1}\r\n", DateTime.Now, data));
}
The viewer Code:
int index = 0;
private void Form1_Load(object sender, EventArgs e)
{
try
{
using (StreamReader sr = new StreamReader(logFilePath))
{
while (sr.Peek() >= 0) // reading the old data
{
AddLineToGrid(sr.ReadLine());
index++;
}
sr.Close();
}
timer1.Start();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void timer1_Tick(object sender, EventArgs e)
{
using (StreamReader sr = new StreamReader(logFilePath))
{
// skipping the old data, it has read in the Form1_Load event handler
for (int i = 0; i < index ; i++)
sr.ReadLine();
while (sr.Peek() >= 0) // reading the live data if exists
{
string str = sr.ReadLine();
if (str != null)
{
AddLineToGrid(str);
index++;
}
}
sr.Close();
}
}
Is there any problem in my code in reading and writing way?
How to solve the problem?
You need to make sure that both the service and the reader open the log file non-exclusively. Try this:
For the service - the writer in your example - use a FileStream instance created as follows:
var outStream = new FileStream(logfileName, FileMode.Open,
FileAccess.Write, FileShare.ReadWrite);
For the reader use the same but change the file access:
var inStream = new FileStream(logfileName, FileMode.Open,
FileAccess.Read, FileShare.ReadWrite);
Also, since FileStream implements IDisposable make sure that in both cases you consider using a using statement, for example for the writer:
using(var outStream = ...)
{
// using outStream here
...
}
Good luck!
Explicit set up the sharing mode while reading the text file.
using (FileStream fs = new FileStream(logFilePath,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite))
{
using (StreamReader sr = new StreamReader(fs))
{
while (sr.Peek() >= 0) // reading the old data
{
AddLineToGrid(sr.ReadLine());
index++;
}
}
}
new StreamReader(File.Open(logFilePath,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite))
-> this doesn't lock the file.
The problem is when you are writing to the log you are exclusively locking the file down so your StreamReader won't be allowed to open it at all.
You need to try open the file in readonly mode.
using (FileStream fs = new FileStream("myLogFile.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (StreamReader sr = new StreamReader(fs))
{
while (!fs.EndOfStream)
{
string line = fs.ReadLine();
// Your code here
}
}
}
I remember doing the same thing a couple of years ago. After some google queries i found this:
FileStream fs = new FileStream(#”c:\test.txt”,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite);
i.e. use the FileShare.ReadWrite attribute on FileStream().
(found on Balaji Ramesh's blog)
Have you tried copying the file, then reading it?
Just update the copy whenever big changes are made.
This method will help you to fastest read a text file and without locking it.
private string ReadFileAndFetchStringInSingleLine(string file)
{
StringBuilder sb;
try
{
sb = new StringBuilder();
using (FileStream fs = File.Open(file, FileMode.Open))
{
using (BufferedStream bs = new BufferedStream(fs))
{
using (StreamReader sr = new StreamReader(bs))
{
string str;
while ((str = sr.ReadLine()) != null)
{
sb.Append(str);
}
}
}
}
return sb.ToString();
}
catch (Exception ex)
{
return "";
}
}
Hope this method will help you.
In C#, if I want to deterministically clean up non-managed resources, I can use the "using" keyword. But for multiple dependent objects, this ends up nesting further and further:
using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
{
using (BufferedStream bs = new BufferedStream(fs))
{
using (StreamReader sr = new StreamReader(bs))
{
// use sr, and have everything cleaned up when done.
}
}
}
In C++, I'm used to being able to use destructors to do it like this:
{
FileStream fs("c:\file.txt", FileMode.Open);
BufferedStream bs(fs);
StreamReader sr(bs);
// use sr, and have everything cleaned up when done.
}
Is there a better way in C# to do this? Or am I stuck with the multiple levels of nesting?
You don't have to nest with multiple usings:
using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
using (BufferedStream bs = new BufferedStream(fs))
using (StreamReader sr = new StreamReader(bs))
{
// all three get disposed when you're done
}
In .NET Core, there's a new using statement which allows you to dispense with the parentheses, and the disposal happens at the end of the current scope:
void MyMethod()
{
using var fs = new FileStream("c:\file.txt", FileMode.Open);
using var bs = new BufferedStream(fs);
using var sr = new StreamReader(bs);
// all three are disposed at the end of the method
}
You can put using statements together before the opening braces like so:
using (StreamWriter w1 = File.CreateText("W1"))
using (StreamWriter w2 = File.CreateText("W2"))
{
// code here
}
http://blogs.msdn.com/ericgu/archive/2004/08/05/209267.aspx
You could use this syntax to condense things down a bit:
using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
using (BufferedStream bs = new BufferedStream(fs))
using (StreamReader sr = new StreamReader(bs))
{
}
This is one of those rare occasions where not using { } for all blocks makes sense IMHO.
I have implemented solutions like Michael Meadows's before, but his StreamWrapper code doesn't take into account if the Dispose() methods called on the member variables throw an exception for one reason or another, the subsequent Dispose()es will not be called and resources could dangle. The safer way for that one to work is:
var exceptions = new List<Exception>();
try
{
this.sr.Dispose();
}
catch (Exception ex)
{
exceptions.Add(ex);
}
try
{
this.bs.Dispose();
}
catch (Exception ex)
{
exceptions.Add(ex);
}
try
{
this.fs.Dispose();
}
catch (Exception ex)
{
exceptions.Add(ex);
}
if (exceptions.Count > 0)
{
throw new AggregateException(exceptions);
}
}
Instead of nesting using statements, you can just write out the .Dispose calls manually - but you'll almost certainly miss one at some point.
Either run FxCop or something else that can make sure that all IDisposable-implementing type instances have a .Dispose() call, or deal with the nesting.
you can omit the curly braces, like:
using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
using (BufferedStream bs = new BufferedStream(fs))
using (StreamReader sr = new StreamReader(bs))
{
// use sr, and have everything cleaned up when done.
}
or use the regular try finally approach:
FileStream fs = new FileStream("c:\file.txt", FileMode.Open);
BufferedStream bs = new BufferedStream(fs);
StreamReader sr = new StreamReader(bs);
try
{
// use sr, and have everything cleaned up when done.
}finally{
sr.Close(); // should be enough since you hand control to the reader
}
This makes for a much larger net plus in lines of code, but a tangible gain in readability:
using (StreamWrapper wrapper = new StreamWrapper("c:\file.txt", FileMode.Open))
{
// do stuff using wrapper.Reader
}
Where StreamWrapper is defined here:
private class StreamWrapper : IDisposable
{
private readonly FileStream fs;
private readonly BufferedStream bs;
private readonly StreamReader sr;
public StreamWrapper(string fileName, FileMode mode)
{
fs = new FileStream(fileName, mode);
bs = new BufferedStream(fs);
sr = new StreamReader(bs);
}
public StreamReader Reader
{
get { return sr; }
}
public void Dispose()
{
sr.Dispose();
bs.Dispose();
fs.Dispose();
}
}
With some effort, StreamWrapper could be refactored to be more generic and reusable.
It should be noted that generally when creating stream based off another stream the new stream will close the one being passed in. So, to further reduce your example:
using (Stream Reader sr = new StreamReader( new BufferedStream( new FileStream("c:\file.txt", FileMode.Open))))
{
// all three get disposed when you're done
}
for this example let us assume you have:
a file named 1.xml under c:\
a textbox named textBox1, with the multi-line properties set ON.
const string fname = #"c:\1.xml";
StreamReader sr=new StreamReader(new BufferedStream(new FileStream(fname,FileMode.Open,FileAccess.Read,FileShare.Delete)));
textBox1.Text = sr.ReadToEnd();
The using statement is syntactic sugar that converts to:
try
{
obj declaration
...
}
finally
{
obj.Dispose();
}
You can explicitly call Dispose on your objects, but it won't be as safe, since if one of them throws an exception, the resources won't be freed properly.