近日做文件操作時,老是拋異常說文件正在被另一個進程占用着,很無奈,給我知道是哪個進程占用的話,就把它給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或標題那幾個操作。求高人點。
