有没有更好的方法来确定文件是否由.NET中的另一个应用程序打开?

Dav*_*rab 1 .net c# file-io

我正在为日志做存档服务.由于某些文件是打开的并且在使用中,因此我不能将它们归档,直到它们不再使用.我可以弄清楚如何查看该文件是否由另一个进程打开的唯一方法是下面的代码.

讨厌代码必须有更好的方法.有没有更好的办法?

try
{
    using (FileStream stream = File.Open("SomeFile.txt", FileMode.Open, FileAccess.ReadWrite))
    {
        // Do nothing just seeing if I could open it.
        return true;
    }
}
catch (IOException)
{
    // Exception so File is in use and can't open
    return false;
}
Run Code Online (Sandbox Code Playgroud)

编辑: 请注意,我不想抓住异常.我宁愿完全避免这个例外.我宁愿有一些神奇的函数,例如IsFileInUser(string fileName),它会返回一个布尔值而不会在下面捕获异常.

我看到的一种方法是使用PInvoke的OpenFile.

Dav*_*rab 6

这就是我想出的.

首先,这是通过例外做这件事的坏方法.

public static bool IsFileInUseBadMethod(string filePath)
{
    if (!File.Exists(filePath))
    {
        return false;
    }

    try
    {
        using (StreamReader reader = new StreamReader(File.Open(filePath, FileMode.Open, FileAccess.ReadWrite)))
        {
            return false;
        }
    }
    catch (IOException)
    {
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的机器上,当文件被使用时,这种方法需要大约1000万个滴答.

另一种方法是使用kernel32.dll

// Need to declare the function from the kernel32
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern Microsoft.Win32.SafeHandles.SafeFileHandle CreateFile(string lpFileName, System.UInt32 dwDesiredAccess, System.UInt32 dwShareMode, IntPtr pSecurityAttributes, System.UInt32 dwCreationDisposition, System.UInt32 dwFlagsAndAttributes, IntPtr hTemplateFile);

private static readonly uint GENERIC_WRITE = 0x40000000;
private static readonly uint OPEN_EXISTING = 3;
Run Code Online (Sandbox Code Playgroud)

这是功能

public static bool IsFileInUse(string filePath)
{
    if (!File.Exists(filePath))
    {
        return false;
    }

    SafeHandle handleValue = null;

    try
    {
        handleValue = FileHelper.CreateFile(filePath, FileHelper.GENERIC_WRITE, 0, IntPtr.Zero, FileHelper.OPEN_EXISTING, 0, IntPtr.Zero);

        bool inUse = handleValue.IsInvalid;

        return inUse;
    }
    finally
    {
        if (handleValue != null)
        {
            handleValue.Close();

            handleValue.Dispose();

            handleValue = null;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这大约有180万个滴答. 与异常方法的差异超过800万.

然而,当文件未被使用意味着没有抛出异常时,"BAD"方法的速度是130万,而kernel32.dll是200万.大约800k刻度更好.因此,如果我知道该文件在1/10的时间内不会被使用,那么使用Exception方法会更好.然而有一次,与kernel32.dll相比,这是一个非常昂贵的滴答操作.