当文件操作遇上进程占用时
近日做文件操作时,老是抛异常说文件正在被另一个进程占用着,很无奈,给我知道是哪个进程占用的话,就把它给Kill掉,当然这样做在一定程度上是有危险的,万一占用文件的进程是那么那么地重要,就不该Kill了,因此这样的做法只能在确保安全的情况下去做,或者是Kill了进程之后带来的不良后果也无关痛痒。上网找了一下,在别的进程占用文件下读写文件的文章很多,但获取占用文章的进程就比较少,在百度上就有人说过用unlocker这种工具,这工具我没去看,感觉也不太适合在这里用吧,如果有dll,提供API那还不错。后来就在谷歌里找到了只那么一篇文章而已,看了之后还终究要用到别的exe,还得另外开进程啊。
这个工具叫handler,从微软里面下载的。只是一个控制台程序而已,双击它运行就可以查看当前系统中正在运行的进程,进程ID,占用的文件等信息。如果给他输入文件名的参数,那就可以知道到时是那些进程在占用着这个文件了,列举的信息中有进程ID,这个很关键,有了pid,那Process就有希望了。
1 //要检查被那个进程占用的文件 2 string fileName = @"C:\Users\Administrator\Desktop\temp\..\temp\WF英文文档(MSDN).doc"; 3 //先格式化一下路径,免得有上面那种路径的话,程序识别不出来 4 fileName = new FileInfo(fileName).FullName; 5 Process tool = new Process(); 6 //下面这段就配置一下启动进程的相关了 7 tool.StartInfo.FileName = @"C:\Users\Administrator\Desktop\temp\handle.exe"; 8 tool.StartInfo.Arguments = fileName + " /accepteula"; 9 tool.StartInfo.UseShellExecute = false; 10 //这里为了在运行的时候不会给那个程序冒出来 11 //Win7下不用也行,但XP就需要了 12 tool.StartInfo.RedirectStandardOutput = true; 13 tool.Start(); 14 tool.WaitForExit(); 15 string outputTool = tool.StandardOutput.ReadToEnd(); 16 17 //正则提取出进程的pid 18 string matchPattern = @"(?<=\s+pid:\s+)\b(\d+)\b(?=\s+)"; 19 MatchCollection mc = Regex.Matches(outputTool, matchPattern); 20 foreach (Match match in mc) 21 { 22 //有了pid,想把进程怎么弄就怎么弄。 23 24 25 }
这里还插一个题外话吧,就是在关进程的时候,用Process类的话有两种方式,一种比较温柔的CloseMainWindow()方法,另一种则是比较野蛮的,Kill()方法,除非WinForm程序的,只能比较野蛮了,之前听同事说是即使用了Kill(),进程还是会杀不干净的,对Kill()和CloseMainWindow()的内部实现机制还不了解,看那个同事是说用进程通讯去关的,要知道那个窗体标题,其实这样感觉挺像用CloseMainWindow()了,但单纯地用进程通讯去关也是有缺陷的,原本那窗体的标题叫Form1的,经过一系列操作之后窗体名改了,或者加上“(未响应)”,单纯写死一个标题太不科学了。用Process实例的MainWindowTitle属性就可以获取到主窗体的标题,可万一碰到的是子窗体用ShowDialog的形式启动时,想关闭子窗体时,CloseMainWindow()、Kill()、进程通讯都做不到了。用Process实例的MainWindowHandle属性可以获取进程的IntPtr对象,这个相当于在进程通信前调用系统API的FindWindow方法,这样用来发送一个WM_CLOSE消息也跟使用MainWindowTitle属性调用FindWindow的差不多,使用IntPtr对象的适用范围更广,其实用Kill()还是用WM_CLOSE消息,哪个强力一点,干净一点,我真知道,如果Kill()万一跟WM_CLOSE效果差不多的话,那也是Kill方便,免了声明系统API方法,IntPtr或标题那几个操作。求高人点。