检查文件是否已被其他进程使用

问题描述

我正在开发一个Form应用程序,该应用程序希望一次在一个网络中的多台计算机上运行。我的应用程序中有一个表格(叫它 Form1),您可以从中编辑位于网络上的XML文件。为了防止该文件被覆盖,我必须确保一次只有一个人可以访问Form1

我的第一个尝试是在XML文件内创建一个属性,以指示某人何时已经在访问Form1。该解决方案的问题在于,在突然断电(如停电)的情况下,该属性不会更改回其正常值,因为从未Form1正确退出。因此,您必须手动更改XML文件中的值。

我当前的解决方是在Form1内部运行一个线程,该线程不断读取文件,直到再次Form1关闭为止。并在允许其他人访问Form1之前检查文件是否已被读取。该解决方案可以正常工作,但效果并不理想,因为我必须要有一个附加文件,其唯一目的是要读取它,因为我不能不断读取XML文件本身而不会引起其他问题。

编辑:由于第一个答案与我当前的解决方案相同,所以这里是我当前解决方案的代码

//CODE INSIDE FORM1

//Create thread which is reading File2
Thread readerThread = new Thread(new ThreadStart(ReadFile2));
readerThread.Start();

private void ReadFile2()
{
    using (FileStream stream = File.Open(pathFile2,FileMode.Open,FileAccess.Read,FileShare.None))
    {
        //Wait until Form1 is being closed
        threadWait.WaitOne();

        stream.Close();
    }
}

//CODE BEFORE ACCESSING FORM1

private bool Form1OpenCheck()
{
    //Check if file2 is being read
    bool noAccess = false;

    try
    {
        using (FileStream stream = File.Open(pathFile2,FileShare.None))
        {
            stream.Close();
        }
    }
    catch (IOException)
    {
        noAccess = true;
    }

    return noAccess;
}

如果有人可以更好地解决此问题,我将不胜感激。谢谢。

解决方法

我正在使用此实现(这不是我的,是写这个的家伙的道具)

    /// <summary>
    /// Checks if a file is ready
    /// </summary>
    /// <param name="sFilename"></param>
    /// <returns></returns>
    public static bool IsFileReady(string sFilename)
    {
        // If the file can be opened for exclusive access it means that the file
        // is no longer locked by another process.
        try
        {
            using (FileStream inputStream = File.Open(sFilename,FileMode.Open,FileAccess.Read,FileShare.None))
            {
                return inputStream.Length > 0;
            }
        }
        catch (Exception)
        {
            return false;
        }
    }
,

您不必更改文件即可专门为您打开文件,只需在您的文件中提及。打开该文件,没有人可以打开它,甚至对于只读文件也是如此:

string fileName = ...
using (var stream = File.Open(fileName,FileShare.None))
{
    // while here,no one else can access the file,not even delete it.
    ...
}
// now others can open the file again.

虽然您使用FileShare.None打开了文件,但是您的进程或其他进程都无法打开文件或以其他任何方式访问文件。如果尝试打开或删除它们,它们将获得异常。参见FileShare Enum

您或其他人只能在关闭流之后将其打开。因此,始终最好在using语句中包含开口。任何异常都会关闭并丢弃流。

顺便说一句,没有fileShare参数的overload of File.Open也以FileShare.None打开。

因此,如果在其他用例中,您只想读取一次文件,而其他人仍可能开始更改文件,则可能是一个好主意,也许使用FileShare.Read打开文件是一个好习惯。 >

,

好,在与同事交谈并集思广益之后,我想出了一个更好的解决方案

Form1内,我创建了一个TCP Socket,它正在侦听到网络内部IPEndPoint的连接。现在,为了检查Form1是否已经在另一台计算机上运行,​​我创建了另一个TCP Socket,它试图连接到同一IPEndPoint。如果连接失败,则表明Form1在其他任何地方都没有运行,我可以安全地打开它。如果连接正常,Form1已经在某个地方打开了,我可以通知用户。