有没有什么方法可以不使用try/catch块来检查文件是否被锁定?

现在,我所知道的唯一方法是打开文件并捕获任何System.IO.IOException。


当前回答

您可以在感兴趣的文件区域上通过互操作调用LockFile。这将不会抛出异常,如果它成功,你将对文件的那一部分(由你的进程持有)拥有一个锁,这个锁将一直持有,直到你调用UnlockFile或你的进程死亡。

其他回答

您可以通过尝试自己先读取或锁定文件来查看文件是否被锁定。

请在这里查看我的回答以了解更多信息。

在Powershell中也是一样

function Test-FileOpen
{
    Param
    ([string]$FileToOpen)
    try
    {
        $openFile =([system.io.file]::Open($FileToOpen,[system.io.filemode]::Open))
        $open =$true
        $openFile.close()
    }
    catch
    {
        $open = $false
    }
    $open
}

您可以在感兴趣的文件区域上通过互操作调用LockFile。这将不会抛出异常,如果它成功,你将对文件的那一部分(由你的进程持有)拥有一个锁,这个锁将一直持有,直到你调用UnlockFile或你的进程死亡。

您还可以检查是否有任何进程正在使用此文件,并像安装程序一样显示必须关闭才能继续的程序列表。

public static string GetFileProcessName(string filePath)
{
    Process[] procs = Process.GetProcesses();
    string fileName = Path.GetFileName(filePath);

    foreach (Process proc in procs)
    {
        if (proc.MainWindowHandle != new IntPtr(0) && !proc.HasExited)
        {
            ProcessModule[] arr = new ProcessModule[proc.Modules.Count];

            foreach (ProcessModule pm in proc.Modules)
            {
                if (pm.ModuleName == fileName)
                    return proc.ProcessName;
            }
        }
    }

    return null;
}

当我遇到类似的问题时,我完成了以下代码:

public class FileManager
{
    private string _fileName;

    private int _numberOfTries;

    private int _timeIntervalBetweenTries;

    private FileStream GetStream(FileAccess fileAccess)
    {
        var tries = 0;
        while (true)
        {
            try
            {
                return File.Open(_fileName, FileMode.Open, fileAccess, Fileshare.None); 
            }
            catch (IOException e)
            {
                if (!IsFileLocked(e))
                    throw;
                if (++tries > _numberOfTries)
                    throw new MyCustomException("The file is locked too long: " + e.Message, e);
                Thread.Sleep(_timeIntervalBetweenTries);
            }
        }
    }

    private static bool IsFileLocked(IOException exception)
    {
        int errorCode = Marshal.GetHRForException(exception) & ((1 << 16) - 1);
        return errorCode == 32 || errorCode == 33;
    }

    // other code

}