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

Posted

技术标签:

【中文标题】检查文件是不是已被其他进程使用【英文标题】:Check if file is already in use by other process检查文件是否已被其他进程使用 【发布时间】:2021-02-10 13:57:21 【问题描述】:

我正在开发一个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, FileMode.Open, FileAccess.Read, FileShare.None))
        
            stream.Close();
        
    
    catch (IOException)
    
        noAccess = true;
    

    return noAccess;

如果有人对此问题有更好的解决方案,我将不胜感激。谢谢。

【问题讨论】:

***.com/questions/53611950/… 如果您在尝试使用文件之前尝试检查文件是否被锁定为单独的步骤,您将遇到基本的竞争条件。代码可以发现该文件可用,但在检查方法返回之前,另一个进程可能会锁定该文件。最好的解决方案是尝试更改文件并捕获和处理适当的异常。 【参考方案1】:

我正在使用这个实现(它不是我的,感谢写这个的家伙)

    /// <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;
        
    

【讨论】:

这几乎是我在当前解决方案中已经在做的检查文件是否正在被读取的工作。但是就像我说的那样,我不能在不引起其他问题的情况下不断地读取 XML 文件本身。所以我一直在寻找另一种解决方案。 你可以让 Form1 用 FileShare.None 打开 XML 文件,然后如果另一个用户试图打开文件,就会导致访问冲突异常。 IMO 比使用一个不断对另一个文件不执行任何操作的整个线程更漂亮、更高效。 我不能这样做的原因是我必须为我的程序的其他部分访问 XML 文件中的数据。如果我经常在 Form1 中打开 XML 文件,那么其他部分将不再起作用。这就是我首先创建第二个文件的原因。 那么也许 FileStream.Lock 方法可能是一种替代方法,您只锁定 FileStream 的一部分。除此之外,我想您当前的解决方案可能足够体面。据我所知,像你这样使用锁定文件并不少见。【参考方案2】:

您不必更改文件以专门为您打开它,只需在您的 File.Open 中提及没有人可以打开它,即使是只读的:

string fileName = ...
using (var stream = File.Open(fileName, FileMode.Open, FileAccess.Read, 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 中打开第二个文件的原因是其他人可以在他们之前检查其他人是否已经在 Form1 中(通过尝试打开第二个文件)访问 Form1 他们自己。一旦有人进入 Form1,他们就可以编辑 XML 文件(第一个文件)。 class System.Windows.Form 是 IDisposable,因此即使崩溃,您也可以确定它会被释放。在 Form.Dispose(bool) 你可以关闭文件。【参考方案3】:

好的,在与同事交谈并进行了一些头脑风暴后,我想出了一个更好的解决方案

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

【讨论】:

以上是关于检查文件是不是已被其他进程使用的主要内容,如果未能解决你的问题,请参考以下文章

检查文件是不是被进程文件句柄锁定

修改 glibc 动态链接器以检查共享库是不是已在另一个进程中加载

如何检查 TCP 端口是不是已被监听?

xmlDocument 已被另一个进程使用

检测打开的文件/设备是不是已被替换/删除

用于多进程读写的Java文件锁[重复]