1. 程式人生 > >如何判斷一個檔案是否被關閉?

如何判斷一個檔案是否被關閉?

做專案的時候遇到了下面這個問題:如何判斷一個開啟的txt檔案是否被關閉?
在開啟一個txt檔案的時候,notepad程式是自動通過檔案路徑的引數首先複製檔案,然後馬上就關閉了檔案通道,這個時候開啟的其實只是notepad程式而不是檔案本身。檔案本身的開啟與關閉是一瞬間的事情。也就是說notepad程式在讀取了檔案以後就馬上將檔案關閉了。(不知道這樣講對不對,還請大家指正。)
那麼我們判斷一個txt檔案是否被關閉其實就是判斷這個notepad這個程序是否關閉。

所以一開始自己想是不是要判斷程序是否被關閉。這樣一來還得遍歷程序判斷notepad程式...而且程序名稱全部都是notepad, 難道還要通過獲取程序ID的方法嗎?。。。。
這個方式似乎比較複雜,然後自己百度了一把看看還有沒有什麼更好的辦法。

最後找到了下面這個方法:
http://topic.csdn.net/t/20030804/05/2104986.html
利用Windows API判斷檔案共享鎖定狀態

鎖是作業系統為實現資料共享而提供的一種安全機制,它使得不同的應用程式,不同的計算機之間可以安全有效地共享和交換資料。要保證安全有效地操作共享資料,必須在相應的操作前判斷鎖的型別,然後才能確定資料是否可讀或可寫,從而為開發出健壯的程式提供切實依據。
同樣,在Windows中,檔案可以共享模式開啟,它也涉及到鎖的操作問題。根據Windows中檔案共享時加鎖範圍的大小,鎖可分為全域性鎖和區域性鎖;全域性鎖以鎖定檔案全部內容為特徵,而區域性鎖以鎖定檔案的區域性內容為特徵,且檔案的鎖定區域不可重複。根據Windows中檔案共享時鎖的操作許可權分類,鎖可分為:讀鎖,寫鎖,讀寫鎖(可讀可寫,全域性鎖)。
利用上述檔案中鎖的區域不可重複的特性,我們可嘗試給指定檔案加一全域性鎖。若加鎖成功,說明指定檔案未被其它程序鎖定;否則,說明有其它程序鎖定了該檔案。這裡,我們利用兩個Windows Api檔案操作函式:OpenFile和CreateFile來實現鎖定狀態的判斷。

具體對CreateFile的第三個引數的共享模式認識還不是很深刻。。。回頭再好好看看windows核心程式設計。。。

接著上幾天的那個問題。
以前都是用WinExec或者是system函式建立的子程序,這次用CreateProcess來獲得它的控制代碼。
CreateProcess函式。這個函式有10個引數。汗~~~~。其實我們主要用到的就是第一個引數,第二個引數,還有最後一個引數。

BOOL WINAPI CreateProcess(
__in_opt LPCTSTR lpApplicationName,
__inout_opt LPTSTR lpCommandLine,
__in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in BOOL bInheritHandles,
__in DWORD dwCreationFlags,
__in_opt LPVOID lpEnvironment,
__in_opt LPCTSTR lpCurrentDirectory,
__in LPSTARTUPINFO lpStartupInfo,
__out LPPROCESS_INFORMATION lpProcessInformation
);

第一個引數是要開啟的應用程式的路徑,第二個引數是命令列引數。最後一個引數是用來返回新建立的程序的控制代碼。
自己仔細看了一下《windows核心程式設計》這本書。但是不怎麼看的懂。。。因為畢竟10個引數要全部看懂的話就比較困難的。
HANDLE OpenNewFile(LPSTR NewFilePath)
{
STARTUPINFOA si = { sizeof(si) };
SECURITY_ATTRIBUTES saProcess, saThread;
PROCESS_INFORMATION piProcess;
saProcess.nLength = sizeof(saProcess);
saProcess.lpSecurityDescriptor = NULL;
saProcess.bInheritHandle = TRUE;
saThread.nLength = sizeof(saThread);
saThread.lpSecurityDescriptor = NULL;
saThread.bInheritHandle = FALSE;
CHAR Command[100];
strcpy(Command, "notepad.exe ");
strcat(Command, NewFilePath);
BOOL fRet =CreateProcessA("C:\\WINDOWS\\SYSTEM32\\NOTEPAD.EXE",
Command, NULL, NULL, FALSE, NULL, NULL, NULL, &si, &piProcess);
if(fRet == TRUE)
return(piProcess.hProcess);
return 0;
}

這段程式碼的前面初始化部分是copy《windows核心程式設計》的。引數LPSTR NewFilePath 是檔案的路徑名稱。
然後這個函式返回一個新建立的程序的控制代碼

HRes = OpenNewFile(NewFilePath);// 獲得建立新程序開啟notepad檔案的控制代碼
WaitForSingleObject(HRes, INFINITE);

下面是WaitForSingleObject這個函式原型:
DWORD WINAPI WaitForSingleObject(
  __in HANDLE hHandle,
  __in DWORD dwMilliseconds
  );
這個函式很簡單,第一個引數就是控制代碼,第二個引數是等待多少時間(以毫秒計算)。這樣就達到了阻塞的效果。
如果是INFNITE,就是等到程序終止的時候才進行下面的程式碼,否則就一直阻塞等待。

這樣一來問題就很好的解決了。

如果是直接用notepad開啟某個檔案,怎麼知道它關閉了呢?其實思路應該還是跟上面的一樣,就是首先獲得這個程序的控制代碼,判斷這個控制代碼是否存在,如果不存在,那麼應該就是結束了。

接下來再來解決上篇部落格裡寫的那個問題。我首先用notepad檔案開啟一個.txt檔案。然後再用CreateFile開啟這個檔案,並且設定第三個引數為0,就是設定共享模式為不共享,這個時候使用CreateFile能開啟檔案並且獲得一個控制代碼,這就說明這個時候notepad程式已經關閉了.txt檔案。
不知道自己講的對不對,有什麼錯誤還懇請大家指正。