在C#中检查文件是否被锁定。
问题的出现的原因是打开由Firefox使用的sqlite数据库时,程序会一直等待异常被抛出,导致程序停止响应。解决方法是使用更好的方法来检查文件是否被锁定,该方法可以在stackoverflow的链接(http://stackoverflow.com/a/20623302/141172)中找到。此外,问题还涉及到如何确定特定的错误码表示特定类型的锁定,以及如何处理位掩码和异常的副作用的问题。
具体解决方法如下:
1. 在FileManager类中添加GetStream方法,该方法根据文件访问权限打开文件流。如果文件被锁定,则会不断尝试打开文件,直到成功为止。如果尝试的次数超过了指定的次数,则抛出自定义的异常MyCustomException。代码如下:
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); } } }
2. 添加IsFileLocked方法,该方法判断异常是否表示文件被锁定。该方法通过调用Marshal.GetHRForException方法获取异常的HRESULT值,并使用位掩码判断是否为特定的错误码。如果是特定的错误码(32或33),则表示文件被锁定。代码如下:
private static bool IsFileLocked(IOException exception) { int errorCode = Marshal.GetHRForException(exception) & ((1 << 16) - 1); return errorCode == 32 || errorCode == 33; }
3. 通过链接(http://msdn.microsoft.com/library/windows/desktop/aa378137.aspx)查看其他可能返回的HRESULT值的含义,以及如何确定32和33代表的是锁定类型。
4. 通过链接(https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382%28v=vs.85%29.aspx)查看更多相关错误码,特别是ERROR_SHARING_VIOLATION和ERROR_LOCK_VIOLATION。
5. 更新catch子句中的代码,使用常量和位掩码来判断是否为特定的错误码。代码如下:
const int ERROR_SHARING_VIOLATION = 0x20; const int ERROR_LOCK_VIOLATION = 0x21; int errorCode = e.HResult & 0x0000FFFF; return errorCode == ERROR_SHARING_VIOLATION || errorCode == ERROR_LOCK_VIOLATION;
通过以上方法,可以检查文件是否被锁定,避免程序因为等待异常而停止响应。
在C#中检查文件是否被锁定的原因是为了避免在文件被锁定时引发异常并提供更好的用户体验。然而,仅仅进行一次独立的文件锁定检查是无用的,因为文件的锁定状态可能在短时间内发生变化。因此,正确的做法是尝试打开文件并在需要文件时处理锁定问题。
下面是解决这个问题的方法:
1. 将文件打开并进行更新的代码块如下:
if (!IsFileLocked(filePath)) { // open and update file }
2. 创建一个方法来检查文件是否被锁定:
public static bool IsFileLocked(string filePath) { try { using (FileStream stream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) { stream.Close(); } } catch (IOException) { return true; } return false; }
3. 如果文件被锁定,可以等待一段时间后重试。如果是其他类型的文件访问问题,应该传播异常。
通过尝试打开文件并在需要文件时处理锁定问题,可以提供更好的用户体验,并避免在文件被锁定时引发异常。这种方法可以应用于各种情况,例如检查IIS日志中的锁定文件,以及其他需要对文件进行操作的场景。在使用异常处理的过程中,需要注意不要将异常作为正常控制流程的一部分。
在C#中,我们可以通过尝试打开文件并在需要文件时处理锁定问题来检查文件是否被锁定。这种方法可以提供更好的用户体验,并避免在文件被锁定时引发异常。通过创建一个方法来检查文件是否被锁定,我们可以在需要的时候调用该方法,并根据返回值来处理文件锁定问题。
检查文件是否被锁定在C#中的问题,出现的原因是Windows以前无法可靠地获取锁定文件的进程列表。为了支持Restart Manager API,Windows开始追踪这些信息。然而,Restart Manager 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; } // 省略其他代码 static public ListWhoIsLocking(string path) { uint handle; string key = Guid.NewGuid().ToString(); List processes = new List (); 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 }; res = RmRegisterResources(handle, (uint)resources.Length, resources, 0, null, 0, null); if (res != 0) throw new Exception("Could not register resource."); res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons); if (res == ERROR_MORE_DATA) { RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded]; pnProcInfo = pnProcInfoNeeded; res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons); if (res == 0) { processes = new List ((int)pnProcInfo); for (int i = 0; i < pnProcInfo; i++) { try { processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId)); } 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; } }
这段代码使用Restart Manager API来获取锁定指定文件的进程列表。它通过调用RmStartSession、RmRegisterResources和RmGetList等API来实现。代码首先开始一个会话,然后注册资源并获取进程列表。最后,返回包含锁定该文件的进程列表的List
这个解决方法是使用Windows的Restart Manager API来实现的,可以可靠地获取锁定文件的进程列表。它适用于Windows Vista及更高版本。通过调用RmStartSession、RmRegisterResources和RmGetList等API,可以获取锁定指定文件的进程列表。这个解决方法是线程安全的,并且可以检测到远程进程锁定文件。