6

I am trying to determine whether or not a file is currently open or being written to using C#. I've seen similar SO questions, all with a similar solution as my code, which attempts a File.Open on a file. But when I run the program with the code below, and I also manually have the file open, I get the unexpected result of "File is currently NOT locked". Any thoughts/suggestions/anything I'm missing?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;

namespace TestIfFileAccessed
{
    class Program
    {
        static void Main(string[] args)
        {
            string path = @"C:\TEMP\testFile.txt";
            FileInfo filepath = new FileInfo(path);

            if (IsFileLocked(filepath)) {
                Console.WriteLine("File is currently locked");
                Console.ReadLine();
            }
            else
            {
                Console.WriteLine("File is currently NOT locked");
                Console.ReadLine();
            }
        }

        public static bool IsFileLocked(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();
            }

            //file is not locked
            return false;
        }
    }
}
kyle_13
  • 1,173
  • 6
  • 25
  • 47
  • At least put a `using(...)` statement on that `file.Open()`. – whoisj Aug 06 '15 at 19:23
  • 1
    Are you sure you're file is locked when you manually open it? – Glorfindel Aug 06 '15 at 19:23
  • 1
    @whoisj What do you think `stream.Dispose()` does that `stream.Close()` doesn't already do? –  Aug 06 '15 at 19:24
  • 1
    Perhaps you're opening the file in a program that reads the file into memory. Maybe this will work if you open it in another program using `FileInfo.Open` and don't close it. Give it a try :) – MushinNoShin Aug 06 '15 at 19:24
  • 2
    Hard to guess what "also manually have the file open" might mean. Well, not what you think it does. Lots of programs that read .txt files just read its content and close the file again. Like Notepad or VS. – Hans Passant Aug 06 '15 at 19:24
  • Hi @Hans Passant, I am actually opening the file in Notepad. – kyle_13 Aug 06 '15 at 19:26
  • I guess what might be a bit more clarification on what I'm looking for is how to simulate an open and/or locked file, like a text file that is currently being written to. I will try what @MushinNoShin suggested. It appears that opening a text file in Notepad, which I'm using, does not actually lock the file. – kyle_13 Aug 06 '15 at 19:30
  • @hvd per the `IDisposable` documentation it releases the underlying native allocations - and per the CoreCLR source code it does so as well. Use if `_handle.Dispose();` seems important. – whoisj Aug 06 '15 at 19:31
  • @whoisj In other words, it does exactly what `stream.Close()` does. Which the OP *is* calling. –  Aug 06 '15 at 19:31
  • @kyle_13 I do not believe that Notepad.exe keeps any kind of read lock on the files it opens. As I understand it, Notepad copies the entire file into memory and the releases the lock. – whoisj Aug 06 '15 at 19:32
  • @hvd ahh I see now `Stream.Dispose(bool)` is `virtual`. Yes, in this case `Close() == Dispose()`. – whoisj Aug 06 '15 at 19:36
  • Either way, you'll have a race condition here. `IsFileLocked` should be renamed to `WasFileLocked`, as when it exits you can't be sure the file wasn't locked again. The only good way to deal with this is to try to open a file handle and keep it open as long as you need to ensure no one else is accessing it. – Lucas Trzesniewski Aug 06 '15 at 19:37
  • Hi @Nicholas Ellingson, testing it out opening the file in Word did indeed lock the file, like I was mistakenly expecting using Notepad. Now, how do I do a similar test that the file is being written to? Or is it one in the same and I can assume my code will work? A side note, once the file is done being written, it just sits there waiting to be processed by my application. So essentially I just need to be sure it's done being written to. – kyle_13 Aug 06 '15 at 19:44

2 Answers2

9

Text files aren't usually locked - their info is usually pulled and loaded into memory, so unless you were trying to access it at the exact same moment that another program is loading the file (which would go very quickly) then you shouldn't have any problems.

Source - Similar question

EDIT: If it is open in word then you will have problems, as Word keeps the stream open. Try opening the file in Word (if you have it) and running your code again, I believe it should work. Otherwise, if you want to see if it's open in Notepad, you would have to scan the current processes running on the system for notepad and check if the process opened the file.

Community
  • 1
  • 1
3

Many text editors don't actually put a file lock on the file. For instance, I use Sublime Text 3 to edit files. I can open an .txt file in Sublime, and open the SAME file in another editor, such as notepad. There is not a filelock on the .txt file.

What is happening is that the file is loaded into memory by the editors when you open them and then closed immediately. They aren't left open. Editors only keep the files open long enough to load them, however, there technically is a lock on the file while the editor is is loading the file into RAM. It just doesn't last very long as this operation is very quick.

You could cause a file lock and see your filelock error as expected if you do filepath.Open(); before you call IsFileLocked(filepath). I would suggest trying this code in your Main method if you want to test this out:

static void Main(string[] args)
{
    string path = @"C:\TEMP\testFile.txt";

    FileInfo filepath = new FileInfo(path);
    Console.WriteLine("Opening \"filepath\"");
    filepath.Open();

    FileInfo filepath2 = new FileInfo(path);

    if (IsFileLocked(filepath2)) {
        Console.WriteLine("File is currently locked");
    }
    else
    {
        Console.WriteLine("File is currently NOT locked");
    }

    Console.WriteLine("Closing \"filepath\"");
    filepath.Close();

    if (IsFileLocked(filepath2)) {
        Console.WriteLine("File is currently locked");
    }
    else
    {
        Console.WriteLine("File is currently NOT locked");
    }
}

I hope this helps to clarify what is going on.

I vow to fall on my sword if this answer turns out to be incorrect and dishonors my family.

Nathan M.
  • 286
  • 1
  • 9
  • thanks. I am seeing now that just opening a file with an application does not necessarily lock it. So if a file is being written to, it is considered "open" and "locked" during that time? I see that this simulates an application opening the file, but I want to confirm that a file being written to is also consider locked. – kyle_13 Aug 06 '15 at 19:51
  • 1
    Yes, if a file is being written to then it is locked. However, for a text file, the writing would be very quick. If you want to simulate opening the file, just open it in word, as word keeps the stream open. – Nicholas Ellingson Aug 06 '15 at 19:52
  • 1
    Yes, a file has to be open and locked to be written to or read from. These operations are super quick and most editors close the files immediately after the operation finishes and uses RAM as it's workspace. Nicholas is correct. If an editor (in this case, Word) doesn't close the file after loading it, the file will remain locked. even thought it's not actively being read from or written to. – Nathan M. Aug 06 '15 at 19:55
  • Thanks for the clarification. What about a file that appears to be written to for some time, when they are in the megabytes (for example 20) in size? Would it be considered locked during the whole write process until it's finished writing in the case of my example? I just wanted to give an example of what I think is a case where the writing is not always quick. – kyle_13 Aug 06 '15 at 19:59
  • Yup, that would be locked during the entire write. You might be surprised by how quickly 20 MB of text is written though :) – Nicholas Ellingson Aug 06 '15 at 20:01
  • Thanks for all your help and explaining. So to my code, whether it's open in Word (for example), or being written to by some other application, they look the same? I don't know of an easy way to simulate the file being written to scenario. – kyle_13 Aug 06 '15 at 20:05
  • 1
    No, different applications handle opening text files differently. So as I was saying, the most common way to open a text file is to lock it, read all of it, and then unlock it right away. Word (and some other programs) handle it by locking it and then keeping it locked the entire time it's open. – Nicholas Ellingson Aug 06 '15 at 20:07
  • 2
    To simulate it (if you want to do so using code) simply make a new project, open the text file using a `var reader = new StreamReader(fileLocation)` and then loop forever using a `while(true)` loop. The file is opened in your reader stream and never closed, making it locked. – Nicholas Ellingson Aug 06 '15 at 20:09
  • Hi @Nicholas Ellingson, thanks, that looping with the StreamReader did the trick for a test. Thanks so much, very cool stuff. – kyle_13 Aug 07 '15 at 13:45
  • No problem, glad I could help you! – Nicholas Ellingson Aug 07 '15 at 13:53