74

I am monitoring a text file that is being written to by a server program. Every time the file is changed the content will be outputted to a window in my program.

The problem is that I can't use the Streamreader on the file as it is being used by another process. Setting up a Filestream with ReadWrite won't do any good since I cannot control the process that is using the file.

I can open the file in notepad. It must be possible to access it even though the server is using it.

Is there a good way around this?

Should I do the following?

  1. Monitor the file
  2. Make a temp copy of it when it changes
  3. Read the temp copy
  4. Delete the temp copy.

I need to get the text in the file whenever the server changes it.

Ryan Gates
  • 4,501
  • 6
  • 50
  • 90
Christoffer
  • 7,470
  • 9
  • 39
  • 55

2 Answers2

158

If notepad can read the file then so can you, clearly the program didn't put a read lock on the file. The problem you're running into is that StreamReader will open the file with FileShare.Read. Which denies write access. That can't work, the other program already gained write access.

You'll need to create the StreamReader like this:

using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var sr = new StreamReader(fs, Encoding.Default)) {
    // read the stream
    //...
}

Guessing at the Encoding here. You have to be careful with this kind of code, the other program is actively writing to the file. You won't get a very reliable end-of-file indication, getting a partial last line is quite possible. In particular troublesome when you keep reading the file to try to get whatever the program appended.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • 3
    Thank you... I didn't realize that FileShare.Read would be incorrect in this case. – Marcel Popescu Jul 06 '14 at 12:46
  • 7
    By using `FileShare.ReadWrite | FileShare.Delete` you can gain access to even more number of files. It's worth trying when `FileShare.ReadWrite` is not enough – Adassko Apr 22 '16 at 13:24
  • @Adassko Or when `FileShare.Read` is not enough, as in this case, and in my particular situation, where I was using that in the same kind of code, and had to switch to `FileShare.ReadWrite` to get it to work. – vapcguy Nov 16 '17 at 21:54
  • @Adassko thank you for that comment this helped with another issue, with EPPlus (a .NET Excel file reader/writer) I did need to use "FileShare.ReadWrite | FileShare.Delete" for reading open Excel files, otherwise I would get an error and was unable to read the file. This fixed it thank you! – DotNET Afficionado Nov 25 '21 at 05:43
19

Use

File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

This should work as long as the other application has not locked the file exclusively.

Community
  • 1
  • 1
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • Thank you. Will that work in combination with a streamreader? Like this: File.Open(path, FileMode.Read, FileAccess.Read, FileShare.ReadWrite); StreamReader reader = new StreamReader(path); – Christoffer Mar 18 '12 at 16:05
  • @Tophe: Of course. IIRC, the `StreamReader` ctor can also take these parameters directly. – SLaks Mar 18 '12 at 16:06
  • How would that look? If I put the FileMode.Open, FileAccess.Read, FileShare.ReadWrite as parameters to the Streamreader it won't work. It says it only takes some encoding parameter. – Christoffer Mar 18 '12 at 16:10
  • Then I remembered incorrectly. Sorry. – SLaks Mar 18 '12 at 16:32
  • 2
    `FileMode.Read` does not exist – SandRock Aug 24 '18 at 17:25