1

So far I've tried everything with no success.

What I try to accomplish is, I want to open and lock a file for a certain time. Right after I've opened and locked the file, I try to open the same file just for reading purpose.

string filePath = "test.ini";

// Open and lock the file
FileStream configurationFile = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
configurationFile.Lock(1, configurationFile.Length);

// Open the same file just to read it
using (FileStream bufferStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    using (StreamReader sr = new StreamReader(bufferStream))
    {
        string line;
        while ((line = sr.ReadLine()) != null)    // <--- Here I get the error
        {
            CustomMessageBox.Show(line);
        }
    }
}

I actually can open the file with FileStream and StreamReader but when it comes to use the StreamReader with for example sr.ReadLine() it throws an exception, that the file is in use by another process.

As it's mentioned here Reading a file used by another process [duplicate] the FileShare attribute should be ReadWrite but this didn't help.

Also I've tried all available encodings like StreamReader(bufferStream, Encoding.*) but that didn't work either.

Is there something simple I'm overlooking?

  • 1
    This is [documented in `LockFile`](https://msdn.microsoft.com/library/windows/desktop/aa365202), which the managed functions wrap: "If the locking process opens the file a second time, it cannot access the specified region through this second handle until it unlocks the region." You must use the first stream for any reading you wish to do as well. – Jeroen Mostert Nov 06 '17 at 20:56
  • Am I understanding that you want to lock the file for writing, while still allowing reading? If that's the case, is this a duplicate of https://stackoverflow.com/q/3279071/120955? – StriplingWarrior Nov 06 '17 at 20:58
  • Since you are going to lock whole file anyway - you can just open it with FileShare.None instead of using Lock. – Evk Nov 06 '17 at 21:04
  • Did you try to open second stream by using first one's `SafeFileHandle` by passing it to constructor with `FileStream(SafeFileHandle handle, FileAccess access)` signature? I believe with proper sharing flags you'll end up with two managed streams bound to single file. – Alex Seleznyov Nov 06 '17 at 21:16
  • @AlexSeleznyov: bound to a single file *handle*. This is important, because the file pointer is associated with that handle (among other things). Particular care should be taken if you go for tricks like these: "`FileStream` assumes that it has exclusive control over the handle. Reading, writing, or seeking while a `FileStream` is also holding a handle could result in data corruption. For data safety, call `Flush` before using the handle, and avoid calling any methods other than `Close` after you are done using the handle." I'd avoid doing this at all. – Jeroen Mostert Nov 06 '17 at 21:21
  • @JeroenMostert thanks for correcting me. Of course. same file and same handle. That was just an idea - never did that in code so might not be the solution for requestor's problem. Thus a comment, not an answer. – Alex Seleznyov Nov 06 '17 at 21:35
  • @StriplingWarrior: Yes this is exactly what I'm trying to do. If I comment out the row where I'm locking the file, it works like it should. – Schrödinger's cat Nov 06 '17 at 21:38

2 Answers2

0

You are calling Lock on the filestream, and passing parameters to indicate that you wish to lock the entire file. According to the documentation,

Locking a range of a file stream gives the threads of the locking process exclusive access to that range of the file stream.

If you don't want the file locked, don't call Lock.

John Wu
  • 50,556
  • 8
  • 44
  • 80
0

That's because according to Windows you're building a new handle to a file. When file is locked it does not allow any other handles to get acquired by other streams. You better fix your code like this:

using (FileStream bufferStream = new FileStream(filePath, FileMode.Open, 
                FileAccess.Read, FileShare.ReadWrite))
{
   bufferStream.Lock(0L, bufferStream.Length);
   using (StreamReader sr = new StreamReader(bufferStream))
   {
       string line;
       while ((line = sr.ReadLine()) != null)    // <--- Here I get the error
       {
         CustomMessageBox.Show(line);
       }
   }

   // dispose lock
   bufferStream.Unlock(0L, bufferStream.Length);
}
Nick Reshetinsky
  • 447
  • 2
  • 13
  • That won't work because a `StreamReader` takes ownership of the stream it's passed, unless you use the [one constructor that allows you to leave the stream open](https://learn.microsoft.com/dotnet/api/system.io.streamreader.-ctor?view=netframework-4.7.1#System_IO_StreamReader__ctor_System_IO_Stream_System_Text_Encoding_System_Boolean_System_Int32_System_Boolean_). By the time you call `.Unlock`, the stream has already been disposed. – Jeroen Mostert Nov 06 '17 at 21:11