Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何检查文件锁定?_C#_.net_Io_Filelock - Fatal编程技术网

C# 如何检查文件锁定?

C# 如何检查文件锁定?,c#,.net,io,filelock,C#,.net,Io,Filelock,有没有办法在不使用try/catch块的情况下检查文件是否被锁定 现在,我知道的唯一方法就是打开文件并捕获任何System.IO.IOException不,不幸的是,如果您仔细想想,这些信息将毫无价值,因为文件可能在下一秒就被锁定(读:short timespan) 为什么特别需要知道文件是否已锁定?知道这一点可能会给我们一些其他的方式给你好的建议 如果您的代码如下所示: if not locked then open and update file 然后在这两行之间,另一个进程可以很

有没有办法在不使用try/catch块的情况下检查文件是否被锁定


现在,我知道的唯一方法就是打开文件并捕获任何
System.IO.IOException
不,不幸的是,如果您仔细想想,这些信息将毫无价值,因为文件可能在下一秒就被锁定(读:short timespan)

为什么特别需要知道文件是否已锁定?知道这一点可能会给我们一些其他的方式给你好的建议

如果您的代码如下所示:

if not locked then
    open and update file
然后在这两行之间,另一个进程可以很容易地锁定文件,这会给您带来一个您试图避免的问题:异常

然后在这两行之间,另一个进程可以很容易地锁定文件,这会给您带来一个您试图避免的问题:异常

但是,通过这种方式,您将知道问题是暂时的,请稍后重试。(例如,您可以编写一个线程,如果在尝试写入时遇到锁,它会一直重试,直到锁消失。)


另一方面,IOException本身不够具体,以至于锁定是IO失败的原因。可能有一些原因不是暂时的。

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


.

您可以通过interop对感兴趣的文件区域进行调用。这不会引发异常,如果成功,您将对文件的该部分(由您的进程持有)拥有一个锁,该锁将一直保持到您调用或进程死亡

您可以使用.NET FileStream类方法Lock和Unlock,而不是使用互操作:

FileStream.Lock

解除锁定

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

public bool IsFileLocked(string filePath)
{
    try
    {
        using (File.Open(filePath, FileMode.Open)){}
    }
    catch (IOException e)
    {
        var errorCode = Marshal.GetHRForException(e) & ((1 << 16) - 1);

        return errorCode == 32 || errorCode == 33;
    }

    return false;
}
public bool IsFileLocked(字符串文件路径)
{
尝试
{
使用(File.Open(filePath,FileMode.Open)){}
}
捕获(IOE异常)
{

var errorCode=Marshal.GetHRForException(e)&(1您还可以检查是否有任何进程正在使用此文件,并显示必须关闭才能像安装程序一样继续的程序列表

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

狄克逊优秀答案的变体(如上)


下面是DixonD代码的一个变体,它增加了等待文件解锁的秒数,然后重试:

public bool IsFileLocked(string filePath, int secondsToWait)
{
    bool isLocked = true;
    int i = 0;

    while (isLocked &&  ((i < secondsToWait) || (secondsToWait == 0)))
    {
        try
        {
            using (File.Open(filePath, FileMode.Open)) { }
            return false;
        }
        catch (IOException e)
        {
            var errorCode = Marshal.GetHRForException(e) & ((1 << 16) - 1);
            isLocked = errorCode == 32 || errorCode == 33;
            i++;

            if (secondsToWait !=0)
                new System.Threading.ManualResetEvent(false).WaitOne(1000);
        }
    }

    return isLocked;
}


if (!IsFileLocked(file, 10))
{
    ...
}
else
{
    throw new Exception(...);
}
public bool IsFileLocked(字符串文件路径,int secondsToWait)
{
bool isLocked=true;
int i=0;
而(isLocked&((ivar errorCode=Marshal.GetHRForException(e)和((1我最后做的是:

internal void LoadExternalData() {
    FileStream file;

    if (TryOpenRead("filepath/filename", 5, out file)) {
        using (file)
        using (StreamReader reader = new StreamReader(file)) {
         // do something 
        }
    }
}


internal bool TryOpenRead(string path, int timeout, out FileStream file) {
    bool isLocked = true;
    bool condition = true;

    do {
        try {
            file = File.OpenRead(path);
            return true;
        }
        catch (IOException e) {
            var errorCode = Marshal.GetHRForException(e) & ((1 << 16) - 1);
            isLocked = errorCode == 32 || errorCode == 33;
            condition = (isLocked && timeout > 0);

            if (condition) {
                // we only wait if the file is locked. If the exception is of any other type, there's no point on keep trying. just return false and null;
                timeout--;
                new System.Threading.ManualResetEvent(false).WaitOne(1000);
            }
        }
    }
    while (condition);

    file = null;
    return false;
}
内部无效加载外部数据(){
文件流文件;
if(TryOpenRead(“文件路径/文件名”,5,输出文件)){
使用(文件)
使用(StreamReader=新StreamReader(文件)){
//做点什么
}
}
}
内部bool TryOpenRead(字符串路径、int超时、out FileStream文件){
bool isLocked=true;
布尔条件=真;
做{
试一试{
file=file.OpenRead(路径);
返回true;
}
捕获(IOE异常){
var errorCode=Marshal.GetHRForException(e)和(10);
如果(条件){
//只有当文件被锁定时,我们才会等待。如果异常是任何其他类型的,那么继续尝试是没有意义的。只需返回false和null;
超时--;
新系统。线程。手动重置事件(错误)。WaitOne(1000);
}
}
}
while(条件);
file=null;
返回false;
}

其他答案依赖于旧信息。此答案提供了更好的解决方案。

很久以前,无法可靠地获取锁定文件的进程列表,因为Windows根本没有跟踪该信息。为了支持,现在跟踪该信息。重新启动管理器API从Windows Vista和Windows Server 2008()开始提供

我将获取文件路径的代码放在一起,并返回锁定该文件的所有进程的
列表

static public class FileUtil
{
    [StructLayout(LayoutKind.Sequential)]
    struct RM_UNIQUE_PROCESS
    {
        public int dwProcessId;
        public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
    }

    const int RmRebootReasonNone = 0;
    const int CCH_RM_MAX_APP_NAME = 255;
    const int CCH_RM_MAX_SVC_NAME = 63;

    enum RM_APP_TYPE
    {
        RmUnknownApp = 0,
        RmMainWindow = 1,
        RmOtherWindow = 2,
        RmService = 3,
        RmExplorer = 4,
        RmConsole = 5,
        RmCritical = 1000
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    struct RM_PROCESS_INFO
    {
        public RM_UNIQUE_PROCESS Process;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)]
        public string strAppName;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)]
        public string strServiceShortName;

        public RM_APP_TYPE ApplicationType;
        public uint AppStatus;
        public uint TSSessionId;
        [MarshalAs(UnmanagedType.Bool)]
        public bool bRestartable;
    }

    [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
    static extern int RmRegisterResources(uint pSessionHandle,
                                          UInt32 nFiles,
                                          string[] rgsFilenames,
                                          UInt32 nApplications,
                                          [In] RM_UNIQUE_PROCESS[] rgApplications,
                                          UInt32 nServices,
                                          string[] rgsServiceNames);

    [DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)]
    static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey);

    [DllImport("rstrtmgr.dll")]
    static extern int RmEndSession(uint pSessionHandle);

    [DllImport("rstrtmgr.dll")]
    static extern int RmGetList(uint dwSessionHandle,
                                out uint pnProcInfoNeeded,
                                ref uint pnProcInfo,
                                [In, Out] RM_PROCESS_INFO[] rgAffectedApps,
                                ref uint lpdwRebootReasons);

    /// <summary>
    /// Find out what process(es) have a lock on the specified file.
    /// </summary>
    /// <param name="path">Path of the file.</param>
    /// <returns>Processes locking the file</returns>
    /// <remarks>See also:
    /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373661(v=vs.85).aspx
    /// http://wyupdate.googlecode.com/svn-history/r401/trunk/frmFilesInUse.cs (no copyright in code at time of viewing)
    /// 
    /// </remarks>
    static public List<Process> WhoIsLocking(string path)
    {
        uint handle;
        string key = Guid.NewGuid().ToString();
        List<Process> processes = new List<Process>();

        int res = RmStartSession(out handle, 0, key);

        if (res != 0)
            throw new Exception("Could not begin restart session.  Unable to determine file locker.");

        try
        {
            const int ERROR_MORE_DATA = 234;
            uint pnProcInfoNeeded = 0,
                 pnProcInfo = 0,
                 lpdwRebootReasons = RmRebootReasonNone;

            string[] resources = new string[] { path }; // Just checking on one resource.

            res = RmRegisterResources(handle, (uint)resources.Length, resources, 0, null, 0, null);

            if (res != 0) 
                throw new Exception("Could not register resource.");                                    

            //Note: there's a race condition here -- the first call to RmGetList() returns
            //      the total number of process. However, when we call RmGetList() again to get
            //      the actual processes this number may have increased.
            res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons);

            if (res == ERROR_MORE_DATA)
            {
                // Create an array to store the process results
                RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded];
                pnProcInfo = pnProcInfoNeeded;

                // Get the list
                res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons);

                if (res == 0)
                {
                    processes = new List<Process>((int)pnProcInfo);

                    // Enumerate all of the results and add them to the 
                    // list to be returned
                    for (int i = 0; i < pnProcInfo; i++)
                    {
                        try
                        {
                            processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId));
                        }
                        // catch the error -- in case the process is no longer running
                        catch (ArgumentException) { }
                    }
                }
                else
                    throw new Exception("Could not list processes locking resource.");                    
            }
            else if (res != 0)
                throw new Exception("Could not list processes locking resource. Failed to get size of result.");                    
        }
        finally
        {
            RmEndSession(handle);
        }

        return processes;
    }
}
静态公共类FileUtil
{
[StructLayout(LayoutKind.Sequential)]
结构RM\u唯一\u进程
{
公共int-dwProcessId;
public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
}
常数int rmrebootreasonone=0;
const int CCH\u RM\u MAX\u APP\u NAME=255;
const int CCH\U RM\U MAX\U SVC\U NAME=63;
枚举RM_应用程序_类型
{
RmUnknownApp=0,
RmMainWindow=1,
RmOtherWindow=2,
RmService=3,
RmExplorer=4,
RmConsole=5,
RmCritical=1000
}
[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)]
结构RM\u流程\u信息
{
公共RM_唯一的流程;
[Marshallas(UnmanagedType.ByValTStr,SizeConst=CCH\u RM\u MAX\u APP\u NAME+1)]
公共字符串名称;
[Marshallas(UnmanagedType.ByValTStr,SizeConst=CCH\u RM\u MAX\u SVC\u NAME+1)]
公共字符串strServiceShortName;
公共RM_应用程序类型应用程序类型;
公共应用状态;
公共uint TSSessionId;
[Marshallas(UnmanagedType.Bool)]
公共布尔布尔表;
}
[DllImport(“rstrtmgr.dll”,CharSet=CharSet.Unicode)]
静态外部内部RmRegisterResources(uint pSessionHandle,
UInt32文件,
字符串[]rgsFilenames,
UInt32应用程序,
[在]RM_唯一_流程[]RGA应用程序中,
UInt32 N服务,
字符串[]rgsServiceNames);
[Dll
internal void LoadExternalData() {
    FileStream file;

    if (TryOpenRead("filepath/filename", 5, out file)) {
        using (file)
        using (StreamReader reader = new StreamReader(file)) {
         // do something 
        }
    }
}


internal bool TryOpenRead(string path, int timeout, out FileStream file) {
    bool isLocked = true;
    bool condition = true;

    do {
        try {
            file = File.OpenRead(path);
            return true;
        }
        catch (IOException e) {
            var errorCode = Marshal.GetHRForException(e) & ((1 << 16) - 1);
            isLocked = errorCode == 32 || errorCode == 33;
            condition = (isLocked && timeout > 0);

            if (condition) {
                // we only wait if the file is locked. If the exception is of any other type, there's no point on keep trying. just return false and null;
                timeout--;
                new System.Threading.ManualResetEvent(false).WaitOne(1000);
            }
        }
    }
    while (condition);

    file = null;
    return false;
}
static public class FileUtil
{
    [StructLayout(LayoutKind.Sequential)]
    struct RM_UNIQUE_PROCESS
    {
        public int dwProcessId;
        public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
    }

    const int RmRebootReasonNone = 0;
    const int CCH_RM_MAX_APP_NAME = 255;
    const int CCH_RM_MAX_SVC_NAME = 63;

    enum RM_APP_TYPE
    {
        RmUnknownApp = 0,
        RmMainWindow = 1,
        RmOtherWindow = 2,
        RmService = 3,
        RmExplorer = 4,
        RmConsole = 5,
        RmCritical = 1000
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    struct RM_PROCESS_INFO
    {
        public RM_UNIQUE_PROCESS Process;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)]
        public string strAppName;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)]
        public string strServiceShortName;

        public RM_APP_TYPE ApplicationType;
        public uint AppStatus;
        public uint TSSessionId;
        [MarshalAs(UnmanagedType.Bool)]
        public bool bRestartable;
    }

    [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
    static extern int RmRegisterResources(uint pSessionHandle,
                                          UInt32 nFiles,
                                          string[] rgsFilenames,
                                          UInt32 nApplications,
                                          [In] RM_UNIQUE_PROCESS[] rgApplications,
                                          UInt32 nServices,
                                          string[] rgsServiceNames);

    [DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)]
    static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey);

    [DllImport("rstrtmgr.dll")]
    static extern int RmEndSession(uint pSessionHandle);

    [DllImport("rstrtmgr.dll")]
    static extern int RmGetList(uint dwSessionHandle,
                                out uint pnProcInfoNeeded,
                                ref uint pnProcInfo,
                                [In, Out] RM_PROCESS_INFO[] rgAffectedApps,
                                ref uint lpdwRebootReasons);

    /// <summary>
    /// Find out what process(es) have a lock on the specified file.
    /// </summary>
    /// <param name="path">Path of the file.</param>
    /// <returns>Processes locking the file</returns>
    /// <remarks>See also:
    /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373661(v=vs.85).aspx
    /// http://wyupdate.googlecode.com/svn-history/r401/trunk/frmFilesInUse.cs (no copyright in code at time of viewing)
    /// 
    /// </remarks>
    static public List<Process> WhoIsLocking(string path)
    {
        uint handle;
        string key = Guid.NewGuid().ToString();
        List<Process> processes = new List<Process>();

        int res = RmStartSession(out handle, 0, key);

        if (res != 0)
            throw new Exception("Could not begin restart session.  Unable to determine file locker.");

        try
        {
            const int ERROR_MORE_DATA = 234;
            uint pnProcInfoNeeded = 0,
                 pnProcInfo = 0,
                 lpdwRebootReasons = RmRebootReasonNone;

            string[] resources = new string[] { path }; // Just checking on one resource.

            res = RmRegisterResources(handle, (uint)resources.Length, resources, 0, null, 0, null);

            if (res != 0) 
                throw new Exception("Could not register resource.");                                    

            //Note: there's a race condition here -- the first call to RmGetList() returns
            //      the total number of process. However, when we call RmGetList() again to get
            //      the actual processes this number may have increased.
            res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons);

            if (res == ERROR_MORE_DATA)
            {
                // Create an array to store the process results
                RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded];
                pnProcInfo = pnProcInfoNeeded;

                // Get the list
                res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons);

                if (res == 0)
                {
                    processes = new List<Process>((int)pnProcInfo);

                    // Enumerate all of the results and add them to the 
                    // list to be returned
                    for (int i = 0; i < pnProcInfo; i++)
                    {
                        try
                        {
                            processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId));
                        }
                        // catch the error -- in case the process is no longer running
                        catch (ArgumentException) { }
                    }
                }
                else
                    throw new Exception("Could not list processes locking resource.");                    
            }
            else if (res != 0)
                throw new Exception("Could not list processes locking resource. Failed to get size of result.");                    
        }
        finally
        {
            RmEndSession(handle);
        }

        return processes;
    }
}
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
}