How to Check If a File Is in Use

Is there a way to check if a file is in use?

Updated NOTE on this solution: Checking with FileAccess.ReadWrite will fail for Read-Only files so the solution has been modified to check with FileAccess.Read.

ORIGINAL:
I've used this code for the past several years, and I haven't had any issues with it.

Understand your hesitation about using exceptions, but you can't avoid them all of the time:

protected virtual bool IsFileLocked(FileInfo file)
{
try
{
using(FileStream stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None))
{
stream.Close();
}
}
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;
}

//file is not locked
return false;
}

Using C# to check if a file is in use

You can get lock a file for exclusive access by using FileStream with FileShare.None. So if we want to implement the first requests mentioned i.e.

  1. check if the file is in use, if yes, inform the user
  2. if not lock it, so no one opens it
  3. copy the file
  4. rename the file

You can implement the following code:

try
{

using (Stream stream = new FileStream("1.docx", FileMode.Open, FileAccess.ReadWrite, FileShare.None))
{
// Here you can copy your file
// then rename the copied file
}
}
catch (Exception ex)
{
MessageBox.Show("File is in use!! Close it and try again");
return;
}

I think you know how to copy and rename the file (if not comment it and I will add the code here).
The second part of your question is a little bit tricky. Because you cannot use Filestream to delete a file. A soon as you dispose the filestream to call File.Delete("YourFile.doc") it is possible that some accesses it exactly in that moment.
I would recommend that you truncate the file when it is locked, so that it unusable for other users. You can also keep your process in a loop until the file is released. The code would look like that:

try
{
using (Stream stream = new FileStream("1.docx", FileMode.Open, FileAccess.ReadWrite, FileShare.None))
{
// Here you can copy your file
// then rename the copied file
using (StreamWriter writer = new StreamWriter(stream, Encoding.Unicode))
{
writer.Write(""); // truncate the file, making it unusable to others
}
}
while (true)
{
try
{
File.Delete("1.docx");
}
catch
{
}
}
}
catch (Exception ex)
{
MessageBox.Show("File is in use!! Close it and try again");
return;
}

Check if file is already in use by other process

Ok after talking to a colleague and a bit of brainstorming I came up with a better solution.

Inside Form1 I create a TCP Socket which is listening for connections to an IPEndPoint inside the network. Now in order to check if Form1 is already running on another machine I create another TCP Socket which is trying to connect to the same IPEndPoint. If the connection fails this means Form1 is running nowhere else and I can safely open it. If the connection works Form1 is already open somewhere and I can inform the user about it.

Check if file is in use

I can't try to open and catch an exception because it will open

Why ? It's a valuable option to work in that way.

By the way you can also create a some empty predefined file, say "access.lock", and others, in order to understand if the actual file is locked check on lock file presence:

if(File.Exist("access.lock")) 
//locked
else
//write something

Check if a file is not open nor being used by another process

An issue with trying to find out if a file is being used by another process is the possibility of a race condition. You could check a file, decide that it is not in use, then just before you open it another process (or thread) leaps in and grabs it (or even deletes it).

Ok, let's say you decide to live with that possibility and hope it does not occur. To check files in use by other processes is operating system dependant.

On Linux it is fairly easy, just iterate through the PIDs in /proc. Here is a generator that iterates over files in use for a specific PID:

def iterate_fds(pid):
dir = '/proc/'+str(pid)+'/fd'
if not os.access(dir,os.R_OK|os.X_OK): return

for fds in os.listdir(dir):
for fd in fds:
full_name = os.path.join(dir, fd)
try:
file = os.readlink(full_name)
if file == '/dev/null' or \
re.match(r'pipe:\[\d+\]',file) or \
re.match(r'socket:\[\d+\]',file):
file = None
except OSError as err:
if err.errno == 2:
file = None
else:
raise(err)

yield (fd,file)

On Windows it is not quite so straightforward, the APIs are not published. There is a sysinternals tool (handle.exe) that can be used, but I recommend the PyPi module psutil, which is portable (i.e., it runs on Linux as well, and probably on other OS):

import psutil

for proc in psutil.process_iter():
try:
# this returns the list of opened files by the current process
flist = proc.open_files()
if flist:
print(proc.pid,proc.name)
for nt in flist:
print("\t",nt.path)

# This catches a race condition where a process ends
# before we can examine its files
except psutil.NoSuchProcess as err:
print("****",err)

How to check if a file is being used by another application?

You need to use GetLastError() to know why CreateFile() failed, eg:

// this is requesting exclusive access to the file, so it will
// fail if the file is already open for any reason. That condition
// is detected by a sharing violation error due to conflicting
// sharing rights...

HANDLE fh = CreateFile("D:\\1.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (fh == INVALID_HANDLE_VALUE)
{
switch (GetLastError())
{
case ERROR_PATH_NOT_FOUND:
case ERROR_FILE_NOT_FOUND:
MessageBox(NULL, "The file does not exist", "Error", 0);
break;

case ERROR_SHARING_VIOLATION:
MessageBox(NULL, "The file is in use", "Error", 0);
break;

//...

default:
MessageBox(NULL, "Error opening the file", "Error", 0);
break;
}
}
else
{
// the file exists and was not in use.
// don't forget to close the handle...
CloseHandle(fh);
}


Related Topics



Leave a reply



Submit