22

I want to open a file for read in exclusive mode, and if the file is already opened by some process/thread else, I want to receive an exception. I tried the following code, but not working, even if I opened the foo.txt, I still can reach the Console.WriteLine statement. Any ideas?

static void Main(string[] args)
{
    using (Stream iStream = File.Open("c:\\software\\code.txt", FileMode.Open,
    FileAccess.Read, FileShare.None))
    {
        Console.WriteLine ("I am here");
    }

    return;
}
MKII
  • 892
  • 11
  • 36
George2
  • 44,761
  • 110
  • 317
  • 455
  • "even if I opened the foo.txt" -> how did you open it? – Mehrdad Afshari Mar 26 '09 at 09:59
  • Yes, Mehrdad. I opened it, then execute my program, still could read Console.WriteLine statement. Any ideas? – George2 Mar 26 '09 at 10:01
  • 1
    With notepad? Notepad doesn't lock the file when running. It reads the file in memory and reopens it for writing when you save. – Mehrdad Afshari Mar 26 '09 at 10:02
  • I think to achieve my purpose (do not operate on this file while other process/thread opened this file), I need to check whether a file is opened or not, correct? – George2 Mar 26 '09 at 10:15

5 Answers5

26

What you are doing is the right thing. Probably you are just testing it incorrectly. You should open it with a program that locks the file when it's open. Notepad wouldn't do. You can run your application twice to see:

static void Main(string[] args)
{
    // Make sure test.txt exists before running. Run this app twice to see.
    File.Open("test.txt", FileMode.Open, FileAccess.Read, FileShare.None);
    Console.ReadKey();
}
Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • Thanks Mehrdad, anyway to check whether a file is already opened by other thread/process? – George2 Mar 26 '09 at 10:13
  • I don't think there is a way to find out if a process has opened a file and is working on it. Technically, the file is no longer open after notepad loads it to memory. I think this is the right way to do it as notepad or other programs can't open it again (to read or save) which is fine, I think. – Mehrdad Afshari Mar 26 '09 at 10:18
  • Thanks Mehrdad, I have tested you are correct. my situation is, a thread is serialization (using XML serialization) to the file, another reader thread is read from this file. I do not want the reader thread to operate on this file while XML serialization is in process, any ideas? – George2 Mar 26 '09 at 10:20
  • This already does achieve it. You'll get IOException if a thread is reading from the file and reader threads will get IOException if they try to open the file while you are writing to it. – Mehrdad Afshari Mar 26 '09 at 10:24
  • Hi Mehrdad, I am using XML Serialization, I am not sure if I need some special settings in order to let the serialization thread locks the file, so that the other reader thread is blocked when using FileShare.None? – George2 Mar 26 '09 at 11:20
  • If you want to *block* the thread, instead of throwing the exception, you'd better use a syncronization mechanism in your application instead of OS file locking. You could use ReaderWriterLock on a shared File object: http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlock.aspx – Mehrdad Afshari Mar 26 '09 at 11:23
  • I have one thread write files with arbitrary file name, another thread read scan the dictionary to read, it is hard to predict the file name also hard to synchronize. Any comments or suggestions – George2 Mar 26 '09 at 11:32
  • Oh, you have many files? Have you considered using a storage engine for that matter? An RDBMS, probably... – Mehrdad Afshari Mar 26 '09 at 11:34
  • File is very big so using RDBMS is not very efficient. (continued) – George2 Mar 26 '09 at 13:37
  • my situation is, one thread is copying file (using File.Move method), and another thread is read from the file. I do not want the reader thread to read a partial of the file while copy is in process(this is why I want to have exclusive open mode), does my code posted solve this issue? – George2 Mar 26 '09 at 13:38
  • It does work in terms of not allowing two operations to be done simultaneously. The problem is that this solution does not *block*. It throws an exception on the thread accessing a locked file. This is why I suggest using a `lock(someObject) { }` strategy to manually sync the threads along with it. – Mehrdad Afshari Mar 26 '09 at 14:18
5

Test it by writing a simple console mode program that opens the file and then waits:

static void Main(string args[])
{
    using (FileStream f = File.Open("c:\\software\\code.txt", FileMode.Open, FileAccess.Read, FileShare.None))
    {
        Console.Write("File is open. Press Enter when done.");
        Console.ReadLine();
    }
}

Run that program from the command line (or another instance of Visual Studio), and then run your program. That way, you can play with different values for FileMode and FileShare to make sure that your program reacts correctly in all cases.

And, no, you don't have to check to see if the file is open first. Your code should throw an exception if the file is already open. So all you have to do is handle that exception.

Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
  • Hi Jim, my situation is, one thread is copying file (using File.Move method), and another thread is read from the file. I do not want the reader thread to read a partial of the file while copy is in process(this is why I want to have exclusive open mode), does my code posted solve this issue? – George2 Mar 26 '09 at 13:36
  • Yes, your code solves that issue. It will not open the file if File.Move is in the middle of copying it. – Jim Mischel Mar 26 '09 at 15:05
  • Jim, how do I know if any(!) program is opening it? Either notepad or something else. Or how do I know if it's being copied right now? –  Sep 25 '12 at 14:46
  • @Grienders: If the call to `File.Open` in this code example fails with an access violation exception, then the file is currently open from another program. You can't tell, however, if somebody is using Notepad to view the file, because Notepad opens the file, reads it into memory, and closes the file. If the file is currently being copied, the program doing the copy will have it open. – Jim Mischel Sep 26 '12 at 21:45
3

What you have done is correct.

If you need what are all files already opened, then there is a way to see by NtQuerySystemInformation

You may get idea from http://www.codeproject.com/KB/shell/OpenedFileFinder.aspx

which gets all the files opened in a directory.. which can be extended to a single file whether opened or not...

lakshmanaraj
  • 4,145
  • 23
  • 12
  • Thanks lakshmanaraj, my situation is, a thread is serialization (using XML serialization) to the file, another reader thread is read from this file. I do not want the reader thread to operate on this file while XML serialization is in process, any ideas? – George2 Mar 26 '09 at 11:21
  • You may lock the file or do a mutex by setting a semaphore to operation – lakshmanaraj Mar 26 '09 at 11:33
  • file name is arbitrary so it is hard to lock. More details, I copy arbitrary files from remote machine to local machine using writer thread, and a reader thread will scan the folder and read information for new coming files – George2 Mar 26 '09 at 13:39
  • (continued) my situation is, one thread is copying file (using File.Move method), and another thread is read from the file. I do not want the reader thread to read a partial of the file while copy is in process(this is why I want to have exclusive open mode), does my code posted solve this issue? – George2 Mar 26 '09 at 13:40
  • Yes, Files are locked automatically while being written during a copy operation so your code will not be able to read from the files during the copy operation. Still you can check status(file) and struct stat->st_mode will give the share mode of the file whether it can be accessed or not. – lakshmanaraj Mar 27 '09 at 03:06
2

I would suggest using the FileAccess.ReadWrite member because some files may already be open but allow you Read access on the file. However, I would guess that in non-exceptional conditions, all files open for Read/Write access would not allow your code to Write to the file.

Of course (as Mehrdad already explained), if you are using an editor such as Notepad to open the file as a test, you will not be able to restrict access because Notepad does not lock the file at all.

Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
Cerebrus
  • 25,615
  • 8
  • 56
  • 70
  • Thanks Cerebrus, you are correct and I am using notepad to open it and run my program to test. Any ideas to check whether a file is opened or not (for example, I want my code to be able to check whether notepad has opened it)? – George2 Mar 26 '09 at 10:17
  • No, I don't think there is... except by catching the IOException in the code that tries to subsequently read the file. – Cerebrus Mar 26 '09 at 10:47
  • My situation is, a thread is serialization (using XML serialization) to the file, another reader thread is read from this file. I do not want the reader thread to operate on this file while XML serialization is in process, any ideas? – George2 Mar 26 '09 at 11:20
2

FileShare.None will only work if another process has also opened the file without allowing it to be shared for reads.

Programs such as Notepad and Visual Studio do not lock text files.

Jakob Christensen
  • 14,826
  • 2
  • 51
  • 81
  • Thanks Jakob, anyway to check whether a file is already opened by other thread/process? – George2 Mar 26 '09 at 10:13
  • Hi Jakob, my situation is, a thread is serialization (using XML serialization) to the file, another reader thread is read from this file. I do not want the reader thread to operate on this file while XML serialization is in process, any ideas? – George2 Mar 26 '09 at 10:19
  • How are you serializing? When serializing you must open the file exclusively (i.e. FileAccess.Write and FileShare.None). – Jakob Christensen Mar 26 '09 at 11:33
  • sorry I am wrong. what I said serialization is not 100% accurate in my situation. (continue) – George2 Mar 26 '09 at 13:39
  • my situation is, one thread is copying file (using File.Move method), and another thread is read from the file. I do not want the reader thread to read a partial of the file while copy is in process(this is why I want to have exclusive open mode), does my code posted solve this issue? – George2 Mar 26 '09 at 13:40
  • Yes, I think your code solves it. Files are locked while being written during a copy operation so your code will not be able to read from the files during the copy operation. – Jakob Christensen Mar 26 '09 at 14:06