HI,
I would like to use the file system as a lock between two processes, on windows xp.
i.e. given a file name "file_lock", a process acquires the lock by trying to create
the file "file_lock" if it doesn't already exist. If already exists, fails to get the lock.
i.e.
FileStream fs=new FileStream("c:\\file_lock, FileMode.CreateNew);
Will this work? Is file creation if file doesn't already exist atomic?
Thanks!
Yes it will work. But not as well as a Mutex for many reasons including:
What if the user doesn't have access to create that file?
When your app crashes, the system cleans up Mutex locks. It won't delete your file for you.
Why introduce the overhead and risk of disk IO unnecessarily? (and I'm not sure if this is possible, but while the file is open, a user can rename or move it, right?)
It's more code.
As the question has been tagged as C#, this answer no longer applies, but I would like to leave it in case it would be helpful for others in the future.
If you're using Java, you could use java.nio.channels.FileLock.
To use it, do something like this:
import java.io.RandomAccessFile;
import java.nio.FileLock;
...
RandomAccessFile raf = new RandomAccessFile(file, "rw");
FileLock lock = raf.getChannel().tryLock(0L, Long.MAX_VALUE, false);
if (lock != null && lock.isValid()) {
// You've acquired the lock!
else {
// You did not acquire the lock
raf.close();
}
Note: This protects against access from other processes, but not other threads. You'll need to use your own internal synchronization for that (locking on raf would probably work).
If you want to use the file as a sync lock i suggest you the next procedure.
Check for the file lock/exists
If file is locked the other process is working
If file doesn't exists or have no lock you can adquire it
Open the file adquiring the lock
This code can help you checking for the lock.
public static bool isFileLocked(string filename)
{
if (!File.Exists(filename)) throw new FileNotFoundException("File not found!", filename);
FileStream fs = null;
try
{
fs = File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
return false;
}
catch (IOException)
{
return true;
}
catch (Exception)
{
throw;
}
finally
{
if (fs != null)
{
fs.Close();
fs = null;
}
}
}
HTH!
Related
Our application needs to lock down a file to read-only when it is opened the first time. I have the code below, which doesn't seem to work anymore.
Now, for some reason, it never triggers the exception when I open a second file and just passes through the first statement every time.
From what I understand, the logic behind this code is this: The first file opens the file with Read/Write (FileAccess.ReadWrite) and sets the file to Read for subsequent users (FileShare.Read).
When it is opened the second time, it will try and open it with Read/Write but is restricted to Read-Only upon which it triggers the exception and goes to the second statement. There it will open the file as Read-Only(FileAccess.Read) and set it back to read-write(FileAccess.ReadWrite) for subsequent users, this to ensure that the first document does not get locked out of its already permitted Write rights, which caused an exception.
I tested this already, it used to work with below code. I can still verify that the read-lock is set. When I open the file in another PDF editor, it cannot save, just read. When I do it in my own application, I can save whenever I want.
Am I missing something, or was there a fluke so that it temporarily worked ?
try
{
m_FileStream = File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.Read);
m_bCanWrite = true;
}
catch (Exception)
{
m_FileStream = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
m_bCanWrite = false;
}
I changed the code so it uses using blocks, with the same params, but the result is also the same.
try
{
FileInfo info = new FileInfo(fileName);
using (FileStream readWriteStream = info.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
{
m_bcanWrite = true;
m_PdfDocument = new PDFDoc(readWriteStream);
}
}
catch (Exception)
{
FileInfo info = new FileInfo(fileName);
using (FileStream readStream = info.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
m_bcanWrite = false;
m_PdfDocument = new PDFDoc(readStream);
}
}
As we figured out in comments - the reason was premature closing of the file stream. Of course when you close filestream - all locks on it are released. It's not a good idea to hold the file open for the duration of the whole application run time as you suggested in comment - just close the file when you are done with it, not sooner but not later.
When using a file stream, and setting FileShare to None, and say two users accessing the same function at the same time want to read/write to that file. Will FileShare.None make the second users request waiting or will the second user's request throw an exception?
//two users get to this this code at the same time
using (FileStream filestream = new FileStream(chosenFile, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
using (StreamReader sr = new StreamReader(filestream))
using (StreamWriter sw = new StreamWriter(filestream))
{
//reading and writing to file
}
Msdn says: None Declines sharing of the current file. Any request to open the file (by this process or another process) will fail until the file is closed.
But will requests keep trying until the filestream is closed?
When a process opean a file for Read/Write with FileShare.None any subsequent access by any process on this same file will result in Acess Denied Exception. To answer your question, Second user will get exception.
MSDN: FileShare.None - Declines sharing of the current file. Any request to open the
file (by this process or another process) will fail until the file is
closed.
There are many ways you can handle these kind of concurrent file access issues, Following code demonstrates a simple approach to tackle this situation.
//Retry 5 times when file access fails
int retryCounter = 5;
while (!isFileAccessSuccess && retryCounter > 0)
{
try
{
//Put file access logic here
//If the file has been accessed successfully set the flag to true
isFileAccessSuccess = true;
}
catch (Exception exception)
{
//Log exception
}
finally
{
//Decrease the retry count
--retryCounter;
}
if (!isFileAccessSuccess)
{
//Wait sometime until initiating next try
Thread.Sleep(10000);
}
}
No, IOException will be thrown an with HResult = -2147024864 and Message = The process cannot access the file 'path' because it is being used by another process.
if you want to synchronize access to a file you can use a named wait handle.
public class FileAcessSynchronizer
{
private readonly string _path;
private readonly EventWaitHandle _waitHandle;
public FileAcessSynch(string path)
{
_path = path;
_waitHandle = new EventWaitHandle(true, EventResetMode.AutoReset, "NameOfTheWaitHandle");
}
public void DoSomething()
{
try
{
_waitHandle.WaitOne();
using (FileStream filestream = new FileStream(chosenFile, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
using (StreamReader sr = new StreamReader(filestream))
using (StreamWriter sw = new StreamWriter(filestream))
{
//reading and writing to file
}
}
finally
{
_waitHandle.Set();
}
}
}
since named wait handle creates a critical section no two threads or processes of your application (that use same name as wait handle name) can execute the codes in it concurrently. So one thread or process enters the section, opens the file in the way that no one can access it (other applications), execute commands and at the end leaves the critical section to allow other threads or processes of your application enters the critical section.
I am trying to delete a folder but am getting the following error message:
The process cannot access the file .it is being used by another process.
string target_dir="D:\\projectpath\\page";
if (Directory.Exists(target_dir))
Directory.Delete(target_dir, false);
How can I resolve this error?
It looks like the file is locked by some other process. This could happen if when reading/writing to it you forgot to dispose the stream reader/writer and you leaked the unmanaged handler to the file.
For example if you used the following code to read from the file:
StreamReader reader = new StreamReader(fileName);
string contents = reader.ReadToEnd();
and you never release the reader, the file will be locked. The proper way is to wrap IDisposable resources such as Streams and StreamReaders in using statements:
using (StreamReader reader = new StreamReader(fileName))
{
string contents = reader.ReadToEnd();
}
If on the other hand the file is locked by some other external process to your application then there's very little you could do about it, other than killing this process.
I think on the surface, your problem should be apparent: the file is in use by something else, so you can't delete the directory it resides in. If there was a way to "force delete" the file, it could cause other programs to crash. I'd recommend catching the error and either logging it or displaying it to the user, so they can decide if they really want to delete the in-use file.
If you MUST delete the file, you could take a look at:
Using C#, how does one figure out what process locked a file?
And once you know what the process is, you can then kill it, which should free up the file. Again, this isn't a good practice and should only be used in exceptional circumstances.
To delete the diectory you must have the correct Permissions.
var target_dir = "D:\\projectpath\page";
var isWriteAccess = false;
try
{
var collection = Directory.GetAccessControl(target_dir)
.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
if (collection.Cast<FileSystemAccessRule>().Any(rule => rule.AccessControlType == AccessControlType.Allow))
{
isWriteAccess = true;
}
}
catch (UnauthorizedAccessException ex)
{
isWriteAccess = false;
}
catch (Exception ex)
{
isWriteAccess = false;
}
if (!isWriteAccess)
{
MessageBox.Show("no access to directory.");
// Handle here close and kill the blocking process
}
else
{
Directory.Delete(target_dir, false);
}
}
This question already has answers here:
Is there a way to check if a file is in use?
(20 answers)
Closed 6 years ago.
Is there a way to find if a file is already open or not?
protected virtual bool IsFileinUse(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();
}
return false;
}
As #pranay rana, but we need to make sure we close our file handle:
public bool IsFileInUse(string path)
{
if (string.IsNullOrEmpty(path))
throw new ArgumentException("'path' cannot be null or empty.", "path");
try {
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read)) { }
} catch (IOException) {
return true;
}
return false;
}
If you mean that you want to check if a file is open before you try to open it, then no. (At least not without going low level and examine every file handle that is open in the system.)
Besides, the information would be old when you get it. Even if the test would return that the file is not open, it could have been opened before you have a chance to use the return value.
So, the proper way to handle the situation is to try to open the file, and handle any error than may occur.
Agreed. I would create a designated class which wraps the open file logic or at least the test (IsFileAvailable). This will allow you to place the exception management with a class specifically responsible and make it reusable. You may even apply further logic, such as testing the file size to see if the file is being written to etc, to give a more detailed response. It will also make your consuming code much cleaner.
I'm downloading a file from a server and opening it using Process.Start() and attaching a file watcher to the file to catch any changes and re-upload them to the server.
Is there anyway to determine when the file has closed using the FileWatcher or any other method? The problem being I can't decide how to stop watching the file and I don't want it watched indefinitely?
Any ideas?
Thanks in advance
Jon
What I did was put a 5 minute loop and just watch for the file to be available. That way I could give it time to free up, but yet still had a definitive time. If it hasn't cleared by 5 minutes in my system something is definetely wrong. You should set your time limit to your circumstances. I got this idea from somewhere, no idea where anymore.
DateTime EndTime = System.DateTime.Now.AddMinutes((double)timeOut);
while (System.DateTime.Now <= EndTime)
{
try
{
using (Stream stream = System.IO.File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
if (stream != null)
{
break;
}
}
}
catch (FileNotFoundException)
{
//
}
catch (IOException)
{
//
}
catch (UnauthorizedAccessException)
{
//
}
System.Threading.Thread.Sleep(sleepTime);
}