如何检查文件锁? [重复]

问题描述 投票:0回答:9
有任何方法可以检查文件是否在不使用try/catch块的情况下锁定?

现在,我知道的唯一方法就是打开文件并捕获任何

System.IO.IOException

	

当我面对类似问题时,我完成了以下代码:
c# .net io filelock
9个回答
188
投票
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 }


163
投票
长,由于Windows根本没有跟踪该信息,因此无法可靠地获取锁定文件的流程列表。 为了支持

RestartManagerAPI,现在跟踪该信息。 重新启动管理器API可以从Windows Vista和Windows Server 2008开始(RestartManager:运行时要求

)。

I组合了符合文件路径并返回所有正在锁定该文件的进程的代码。 List<Process> update

thehere是另一个使用示例代码

如何使用RESTART MANAGAR API。
    

不幸的是,如果您考虑一下,那么无论如何,该信息将是毫无价值的,因为该文件可能会锁定下一个第二秒(请读:短时间pan)。
为什么您需要知道该文件是否还是锁定的?知道这可能会给我们一些其他给您好的建议的方法。

如果您的代码看起来像这样:

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

到两行之间,另一个过程可以轻松锁定文件,从而使您与试图避免的相同问题开始:异常。

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

if not locked then open and update file

133
投票

使用Interop使用,您可以使用.NET FILESTREAM类方法锁定并解锁:

filestream.lock

http://msdn.microsoft.com/en-us/library/system.io.filestream.lock.aspx

filestream.unlock
http://msdn.microsoft.com/en-us/library/system.io.filestream.unlock.aspx


16
投票
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; }

usage:

public static bool TryOpen(string path,
                           FileMode fileMode,
                           FileAccess fileAccess,
                           FileShare fileShare,
                           TimeSpan timeout,
                           out Stream stream)
{
    var endTime = DateTime.Now + timeout;

    while (DateTime.Now < endTime)
    {
        if (TryOpen(path, fileMode, fileAccess, fileShare, out stream))
            return true;
    }

    stream = null;
    return false;
}

public static bool TryOpen(string path,
                           FileMode fileMode,
                           FileAccess fileAccess,
                           FileShare fileShare,
                           out Stream stream)
{
    try
    {
        stream = File.Open(path, fileMode, fileAccess, fileShare);
        return true;
    }
    catch (IOException e)
    {
        if (!FileIsLocked(e))
            throw;

        stream = null;
        return false;
    }
}

private const uint HRFileLocked = 0x80070020;
private const uint HRPortionOfFileLocked = 0x80070021;

private static bool FileIsLocked(IOException ioException)
{
    var errorCode = (uint)Marshal.GetHRForException(ioException);
    return errorCode == HRFileLocked || errorCode == HRPortionOfFileLocked;
}

14
投票
there是Dixond代码的变体,它添加了秒数以等待文件解锁,然后重试:

private void Sample(string filePath) { Stream stream = null; try { var timeOut = TimeSpan.FromSeconds(1); if (!TryOpen(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, timeOut, out stream)) return; // Use stream... } finally { if (stream != null) stream.Close(); } }

您可以通过Interop在您感兴趣的文件区域上拨打

lockfile。这不会引发例外,如果成功,您将在文件的该部分上锁定(由您的流程持有),锁将被保留,直到您致电unlockfile

或您的过程死亡。

9
投票

到两行之间,另一个过程可以轻松锁定文件,从而使您与试图避免的相同问题开始:异常。

,无论如何,您会知道问题是暂时的,并在以后重试。 (例如,您可以编写一个线程,如果尝试写作时遇到锁,请继续重试直到锁定为止。) 另一方面,IOException本身并不足够具体,即锁定是IO失败的原因。可能不是临时的原因。

您可以通过先尝试阅读或锁定该文件是否锁定文件。 

7
投票

请请参见我的答案,以获取更多信息。

same的东西,但在powershell

5
投票

我最终做的是: 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 }


4
投票
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.