The following code is expected to work like Excel and inform the user that they can only access the spreadsheet in read-only mode:
.lock
file.lock
file so that the user can e.g. discuss with the person who accesses the fileIn order to reproduce, run the program 2 times, instance 1 can run without debugging. Run the second instance with debugger attached to see the IOException
.
using System;
using System.IO;
using System.Text;
namespace SingleUser
{
internal class Program
{
static void Main(string[] args)
{
string lockFileName = ".lock";
// Make sure that CreateNew can be used in the next step
try
{
File.Delete(lockFileName);
}
catch (IOException) { }
try
{
// First process enters here and gets access
using (var lockfile = File.Open(lockFileName, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read))
{
using (var writer = new StreamWriter(lockfile, Encoding.UTF8, 256, true))
{
string userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
writer.WriteLine(userName);
writer.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
}
// IOException: The segment is already unlocked
// lockfile.Unlock(0,lockfile.Length);
Console.WriteLine("You can access the data. Press Enter to stop working with the file.");
Console.ReadLine();
}
}
catch (IOException e)
{
// Second process enters here and gets info about the user who is working with the data
using (var infofile = File.Open(lockFileName, FileMode.Open, FileAccess.Read)) // <-- fails
{
using (var reader = new StreamReader(infofile, Encoding.UTF8, false, 256, true))
{
string user = reader.ReadLine();
string time = reader.ReadLine();
Console.WriteLine($"{user} works on the file since {time}.");
}
}
Console.WriteLine("You can't modify the data. Press Enter to stop.");
Console.ReadLine();
}
}
}
}
Above code does not work due to an IOException in the line
using (var infofile = File.Open(lockFileName, FileMode.Open, FileAccess.Read)) // <-- fails
But Notepad++ can open the file without problems and copying works as well. So, somehow it seems to be possible to read the file.
As Hans Passant confirms this:
If notepad can read the file then so can you, clearly the program didn't put a read lock on the file.
I have tried Unlock()
as mentioned here
lockfile.Unlock(0,lockfile.Length);
in the place where the comment is in above code, but that gives me
IOException: The segment is already unlocked
I have read this answer by Hans Passant, which says
First try to open the file with FileAccess.ReadWrite and FileShare.Read. If you don't get an IOException, you'll have exclusive write access to the file. Other processes can read from the file but can never gain write access.
Which, IMHO, is exactly what I am trying here.
I'm still on .NET Framework 4.7.2, if that matters. The file is a local file (but the same for a network file).
So, can someone clarify why my code isn't working and how to make it work?
The second process, which is reading the file, needs to allow the first process to make changes to the file. Therefore, FileShare must be set to FileShare.ReadWrite
.
using (var infofile = File.Open(lockFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) // <-- no longer fails
Note that the writing process still is FileShare.Read
.
It looks a bit crazy, if you only have read access and grant someone else write access, but this is not about permissions. Think like this: you have read access and can deal with someone's write access.