I want to create a file ONLY if it doesn't already exists.
A code like:
if (!File.Exists(fileName))
{
fileStream fs = File.Create(fileName);
}
Leave it open for a race-condition in case the file will be created between the "if" to the "create".
How can I avoid it?
EDIT:
locks can't be used here because it's a different processes (multiple instances of the same application).
You can also use
FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate);
However, you should look into thread locking as if more than one thread tries to access the file you'll probably get an exception.
Kristian Fenn answer was almost what I needed, just with a different FileMode. This is what I was looking for:
FileStream fs = new FileStream(fileName, FileMode.CreateNew);
Is this not a better solution. Also notice the using(var stream...) Use it to close the stream to avoid IO Exceptions.
if (!File.Exists(filePath))
{
using (var stream = File.Create(filePath)) { }
}
If the contending attempts to create the file are in the same process, you can use a lock statement around your code to prevent contention.
If not, you may occasionally get an exception when you call File.Create. Just appropriately handle that exception. Checking whether the file exists before creating is probably advisable even if you are handling an exception when the file does exist because a thrown exception is relatively expensive. It would not be advisable only if the probability of the race condition is low.
First you Lock or Monitor.Enter or TryEnter APIs to lock the portion of the code.
Second you can use FileStream API with FileMode.OpenOrCreate API. If the file exists, it just uses it or else it just creates it.
Related
I'm writing a Stringbuilder to file
using (FileStream file = new FileStream(Filepath, FileMode.Append, FileAccess.Write, FileShare.Read))
using (StreamWriter writer = new StreamWriter(file, Encoding.Unicode))
{
writer.Write(text.ToString());
}
This is equivilent (I think)
File.AppendAllText(Filepath, text.ToString());
Obviously in a multi threaded environment these statements on their own would cause failures to write as they collided.
I've put a lock on this code, but that isn't ideal, as it's too expensive and may exacerbate this bottleneck. Is there some other way of causing one threads file access to block another's. I've been told "blocking not locking", I thought lock did block, but they must be hinting at a cheaper way of preventing simultaneous use of the file system.
How do I block execution in a less time expensive manner?
You can't have multiple threads write to the same file simultaneously, thus, there is no such "bottleneck" . A lock makes perfect sense for this scenario. If you are concerned about this being expensive, just add the writes to a queue, and let a single thread manage writing them to file.
Pseudo code
public static readonly Object logsLock = new Object();
// any thread
lock(logsLock)
{
logs.Add(stringBuilderText);
}
// dedicated thread to writing
lock(logsLock)
{
// ideally, this should be a "get in, get out" situation,
// where you only need to make a copy of the logs, then exit the lock,
// then write them, then lock the logsLock again, and remove only the logs
// you successfully wrote to to file, then exit the lock again.
logs.ForEach(writeLogToFile);
}
You can lock the stream using the lock method.
http://msdn.microsoft.com/en-us/library/system.io.filestream.lock.aspx
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Wait until file is unlocked in .NET
I have an open file, like a .Doc or .txt, and I have to wait until the user close it.
I already try this, according to Wait until file is unlocked in .NET :
while (true)
{
try
{
using (FileStream Fs = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None, 100))
{
//the file is close
break;
}
}
catch (IOException)
{
//wait and retry
Thread.Sleep(1000);
}
}
This works well ,but it may be possible to find a solution without a try/catch and handler the exception ?
Unfortunately no, there is no other way.
The API doesn't have an event that will fire when a file in unlocked or anything else that is convenient.
Retrying with waits is the best solution with the current API.
For one, though, don't use the loop you have right now, breaking if there's no exception - perform your actual file access in that using loop.
Next, if the file is open in a known process, you could get its Process object, set EnableRaisingEvents to true, and handle its Exited event to try again. It's not failsafe, though, so you would still handle exceptions and use a loop.
You can make P/Invoke calls to native CreateFile function and then analyze error code. However, try/catch will still be necessary.
I have 2 threads that communicate by sending files to each other. When Thread #1 does a
// Thread #1
File.Create(#"C:\somedir\response.done");
Then Thread #2 is supposed to delete it.
// Thread #2
while (!File.Exists(#"C:\somedir\response.done"))
Thread.Sleep(100);
while (File.Exists(#"C:\somedir\response.done"))
{
try {
File.Delete(#"C:\somedir\response.done");
}
catch { Thread.Sleep(1000); };
}
However, the file seems to be locked. There is generated a response.done file in the directory, but it is never deleted. When I try to manually remove it, then
"The action cannot be completed because the file is open in MyProgram. Close the file and try again."
How can I avoid this?
File.Create returns a FileStream. So... close it:
using(File.Create(path)) {
// add contents here if needed
}
The using ensures it is Dispose()d, hence closed. Note: it is also possible that some AV systems will interfere with file access, but that is usually not a huge problem.
You need to close FileStream created by File.Create(#"C:\somedir\response.done");.
You can also use .Close()
So your code would become
// Thread #1
File.Create(#"C:\somedir\response.done").Close();
change your code to
// Thread #1
using (FileStream FS = File.Create(#"C:\somedir\response.done") ) {};
I have the following lines of code:
xslt.Load(XmlReader.Create(new FileStream(#"C:\website\TransList.xslt", System.IO.FileMode.Open)));
xslt.Transform(mydoc.CreateReader(),null, sw);
It works fine, if I stop the project and launch it again, I get the following error:
[System.IO.IOException] = {"The process cannot access the file 'C:\website\TransList.xslt' because it is being used by another process."}
I then have have to goto the command line and do a IISRESET to get, I can also reset the app pool, this is easiest at this time as this is just my dev box.
Now I do have the call in a try catch statement, but I cannot access the xslt object in the handler.
The xslt object doesn't seem to have a close or dispose method.
The garbage collector never gets a shot at it , it seems.
Any ideas?
You will need to close your FileStream and Reader, either explicitly using .Close() or via a using statement:
using (FileStream fs = new FileStream(#"C:\website\TransList.xslt", System.IO.FileMode.Open))
{
xslt.Load(XmlReader.Create(fs));
using (var reader = mydoc.CreateReader())
{
xslt.Transform(reader, null, sw);
}
}
There is no need to explicitly create a FileStream and an XmlReader, if you know the file location then you can simply pass that to the Load method, using this overload:
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(#"C:\website\Translist.xslt");
If you think you need to create a FileStream and an XmlReader then I agree with the suggestions already made, use the 'using' statement to properly close and dispose of those objects.
Filestream implements IDisposable and requires you to invoke Dispose to release external resources as well as implicit;y invoke close(). You should wrap your instantiation of Filestream in a using block as it ensures Dispose is invoked even if an exception is raised. To answer your question though, since you did not close the filestream, your process, presumably the w3wp.exe process still has a handle on the file stream and the only way you can release is it to reset iis or recycle the app pool. For future reference, just wrap the filestream in a using block to be safe.
I have two ASP.NET web application. One is responsible for processing some info and writing to a log file, and the other application is reponsible for reading the log file and displays the information based on user request.
Here's my code for the Writer
public static void WriteLog(String PathToLogFile, String Message)
{
Mutex FileLock = new Mutex(false, "LogFileMutex");
try
{
FileLock.WaitOne();
using (StreamWriter sw = File.AppendText(FilePath))
{
sw.WriteLine(Message);
sw.Close();
}
}
catch (Exception ex)
{
LogUtil.WriteToSystemLog(ex);
}
finally
{
FileLock.ReleaseMutex();
}
}
And here's my code for the Reader :
private String ReadLog(String PathToLogFile)
{
FileStream fs = new FileStream(
PathToLogFile, FileMode.Open,
FileAccess.Read, FileShare.ReadWrite);
StreamReader Reader = new StreamReader(fs);
return Reader.ReadToEnd();
}
My question, is the above code enough to prevent locking in a web garden environemnt?
EDIT 1 : Dirty read is okay.
EDIT 2 : Creating Mutex with new Mutex(false, "LogFileMutex"), closing StreamWriter
Sounds like your trying to implement a basic queue. Why not use a queue that gives you guarenteed availability. You could drop the messages into an MSMQ, then implement a windows service which will read from the queue and push the messages to the DB. If the writting to the DB fails you simply leave the message on the queue (Although you will want to handle posion messages so if it fails cause the data is bad you don't end up in an infinite loop)
This will get rid of all locking concerns and give you guarenteed delivery to your reader...
You should also be disposing of your mutex, as it derives from WaitHandle, and WaitHandle implements IDisposable:
using (Mutex FileLock = new Mutex(true, "LogFileMutex"))
{
// ...
}
Also, perhaps consider a more unique name (a GUID perhaps) than "LogFileMutex", since another unrelated process could possibly use the same name inadvertantly.
Doing this in a web based environment, you are going to have a lot of issues with file locks, can you change this up to use a database instead?
Most hosting solutions are allowing up to 250mb SQL databases.
Not only will a database help with the locking issues, it will also allow you to purge older data more easily, after a wile, that log read is going to get really slow.
No it won't. First, you're creating a brand new mutex with every call so multiple threads are going to access the writing critical section. Second, you don't even use the mutex in the reading critical section so one thread could be attempting to read the file while another is attempting to write. Also, you're not closing the stream in the ReadLog method so once the first read request comes through your app won't be able to write any log entries anyway until garbage collection comes along and closes the stream for you... which could take awhile.