File locking - read then write whilst locked

痴心易碎 提交于 2019-12-22 17:51:50

问题


I need to be able to open a file to read it, maintaining a lock that denies other instances of the same application write access until I have written the amended file back to disk. The file is in a shared location on a network, and the app instances can be on any machine on the network.

I have tried using a FileStream with FileAccess.ReadWrite and FileShare.Read, with a Streamreader to read and then a StreamWriter (on the same FileStream) to write, but this corrupts the file. Other permutations of the FileAccess and FileShare don't seem to solve my basic problem either.

So I tried closing the StreamReader before opening the StreamWriter, but that changes the CanRead and CanWrite properties of the FileStream, so I still can't write.

Clearly I am taking the wrong approach, so can someone tell me how I should be approaching this? It seems a common enough thing to want to do - edit a file and block write access until the edited file is saved.


回答1:


If you want to write to a file, you need to take exclusive file access, otherwise other programs can read partially written data (your writes aren't atomic). There are solutions to this, but they are quite complex.

A solution could be something like this:

static bool Read(FileStream fs, byte[] data, long position)
{
    fs.Seek(position, SeekOrigin.Begin);

    if (fs.ReadByte() == 0)
    {
        // Block of data not finished writing
        return false;
    }

    fs.Read(data, 0, data.Length);
    return true;
}

static bool Write(FileStream fs, byte[] data, long position)
{
    try
    {
        fs.Lock(position, data.Length + 1);
        fs.Seek(position, SeekOrigin.Begin);
        fs.WriteByte(0);
        fs.Write(data, 0, data.Length);
        fs.Seek(position, SeekOrigin.Begin);
        fs.WriteByte(1);
        fs.Unlock(position, data.Length + 1);
        return true;
    }
    catch (IOException)
    {
        return false;
    }
}

static bool Append(FileStream fs, byte[] data)
{
    return Write(fs, data, fs.Length);
}

where you always keep open the FileStream as

FileStream fs1 = new FileStream("Test.txt", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);

Before the data there is a "guard byte" that tells if the data is being written. If it's being written then reads on it will fail. The file is locked "where it's needed" using FileStream.Lock.

This clearly works better with binary fixed-length data. If you have variable length data (or you need to atomically update more "regions" of a file) then it becomes more complex. Normally you use DBs for this reason :-)




回答2:


Keep the file open with write access. That should deny all other writes to the file.




回答3:


As you don't specify what OS you're using nor whether access is time critical or order critical then I think that your best bet is to use a directory to indicate that the file is locked.

On most OS, creating a directory is pretty much instant, whereas creating a file isn't. So each time your application wants access to the data file in question it must try and create a subdirectory in the same location as the file. If the directory already exists then the create will fail and your application must wait, trying again until it succeeds.

When it succeeds in creating the directory it can access the file and write it. Once all data has been written and file access closed then it should wait for a bit (to allow the actual write to complete) before deleting the directory.

You will, however, need to write some code that can handle an instance of your application crashing and leaving the lock directory present.



来源:https://stackoverflow.com/questions/7914102/file-locking-read-then-write-whilst-locked

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!