CreateFile 函式可以建立新的檔案或開啟現有的檔案。 您必須指定檔名、建立指示和其他屬性。 當應用程式建立新的檔案時,作業系統會將它新增至指定的目錄。
在應用程式中操作檔案
作業系統會將一個稱為 句柄 的唯一識別碼指派給使用 CreateFile 開啟或建立的每個檔案。 應用程式可以使用這個句柄搭配讀取、寫入和描述檔案的函式。 只要該句柄的所有參考未被關閉,它就是有效的。 當應用程式啟動時,如果這些句柄是建立為可繼承的,它會繼承啟動它的程序中的所有開啟中的句柄。
應用程式應該先檢查 CreateFile 傳回的句柄值,再嘗試使用句柄來存取檔案。 如果發生錯誤,句柄值將會 INVALID_HANDLE_VALUE ,而且應用程式可以使用 GetLastError 函式來取得延伸的錯誤資訊。
當應用程式使用 CreateFile 時,它必須使用 dwDesiredAccess 參數來指定它是否打算從檔案讀取、寫入檔案、讀取和寫入,或兩者都不是。 這稱為要求 存取模式。 應用程式也必須使用 dwCreationDisposition 參數來指定檔案已經存在時要採取的動作,稱為 建立處置。 例如,應用程式可以呼叫 createFile ,並將 dwCreationDisposition 設定為 CREATE_ALWAYS ,以一律建立新的檔案,即使已有相同名稱的檔案存在(因此會覆寫現有的檔案)。 這是否成功取決於上一個檔案的屬性和安全性設定等因素(如需詳細資訊,請參閱下列各節)。
應用程式也會使用 CreateFile 來指定它是否要共用檔案以供讀取、寫入或兩者皆否。 這稱為 共用模式。 未共享的開啟檔案(dwShareMode 設定為零)在其把手未關閉之前,無論是開啟它的應用程式,還是其他應用程式都無法再次開啟。 這也稱為獨佔存取權。
當進程使用 CreateFile 嘗試開啟已以共用模式開啟的檔案時(dwShareMode 設定為有效的非零值),系統會比較要求的存取和共用模式與開啟檔案時所指定的檔案。 如果您指定與上一個呼叫中指定的模式衝突的存取或共用模式, CreateFile 會失敗。
下表說明兩個呼叫 CreateFile 的有效組合,分別使用各種存取模式和共用模式(dwDesiredAccess、 dwShareMode )。 CreateFile 函式的呼叫順序並不重要。 不過,每個檔句柄上任何後續的檔案 I/O 作業仍會受到與該特定檔句柄相關聯的目前存取和共用模式所限制。
| 第一次呼叫 CreateFile | CreateFile 的有效第二次呼叫 |
|---|---|
| GENERIC_READ,FILE_SHARE_READ |
-
GENERIC_READ, FILE_SHARE_READ - GENERIC_READ, FILE_SHARE_READ, FILE_SHARE_WRITE |
| GENERIC_READ,FILE_SHARE_WRITE |
-
GENERIC_WRITE,FILE_SHARE_READ - GENERIC_WRITE, FILE_SHARE_READFILE_SHARE_WRITE |
| GENERIC_READ、 FILE_SHARE_READ、 FILE_SHARE_WRITE |
-
GENERIC_READ,FILE_SHARE_READ - GENERIC_READ、 FILE_SHARE_READ、 FILE_SHARE_WRITE - GENERIC_WRITE, FILE_SHARE_READ - GENERIC_WRITE、 FILE_SHARE_READ、 FILE_SHARE_WRITE - GENERIC_READGENERIC_WRITE, FILE_SHARE_READ - GENERIC_READGENERIC_WRITE、FILE_SHARE_READ、FILE_SHARE_WRITE |
| GENERIC_WRITE,FILE_SHARE_READ |
-
GENERIC_READ, FILE_SHARE_WRITE - GENERIC_READ、 FILE_SHARE_READ、 FILE_SHARE_WRITE |
| GENERIC_WRITE,FILE_SHARE_WRITE |
-
GENERIC_WRITE, FILE_SHARE_WRITE - GENERIC_WRITE、 FILE_SHARE_READ、 FILE_SHARE_WRITE |
| GENERIC_WRITE、 FILE_SHARE_READ、 FILE_SHARE_WRITE |
-
GENERIC_READFILE_SHARE_WRITE - GENERIC_READ、 FILE_SHARE_READ、 FILE_SHARE_WRITE - GENERIC_WRITE, FILE_SHARE_WRITE - GENERIC_WRITE、 FILE_SHARE_READ、 FILE_SHARE_WRITE - GENERIC_READ、 GENERIC_WRITE、 FILE_SHARE_WRITE - GENERIC_READ、 GENERIC_WRITE、 FILE_SHARE_READ、 FILE_SHARE_WRITE |
| GENERIC_READ、GENERIC_WRITE、FILE_SHARE_READ | - GENERIC_READ、 FILE_SHARE_READ、 FILE_SHARE_WRITE |
| GENERIC_READ、 GENERIC_WRITE、 FILE_SHARE_WRITE | - GENERIC_WRITE、 FILE_SHARE_READ、 FILE_SHARE_WRITE |
| GENERIC_READ、GENERIC_WRITE、FILE_SHARE_READ、FILE_SHARE_WRITE |
-
GENERIC_READ、 FILE_SHARE_READ、 FILE_SHARE_WRITE - GENERIC_WRITE、 FILE_SHARE_READ、 FILE_SHARE_WRITE - GENERIC_READ、 GENERIC_WRITE、 FILE_SHARE_READ、 FILE_SHARE_WRITE |
除了標準檔案屬性之外,您也可以將 SECURITY_ATTRIBUTES 結構的指標納入為 CreateFile 的第四個參數,來指定安全性屬性。 不過,基礎檔系統必須支援安全性,才能產生任何影響(例如,NTFS 檔案系統支援它,但各種 FAT 檔案系統則不支援)。 如需安全性屬性的詳細資訊,請參閱 存取控制。
建立新檔案的應用程式可以提供範本檔案的選擇性句柄, CreateFile 會從中取得檔案屬性和擴充屬性,以建立新檔案。
CreateFile 案例
使用 CreateFile 函式來起始檔案存取權有幾個基本案例。 這些摘要如下:
- 當具有該名稱的檔案不存在時,請建立新的檔案。
- 即使已存在同名檔案,仍建立新檔案,清空其數據並從頭開始。
- 只在已有的檔案存在且完整無損時才開啟。
- 只有在現有檔案存在時,才開啟現有的檔案,將其截斷為空白。
- 一律依情況開啟檔案:如果檔案存在,則按原樣打開;如果檔案不存在,則建立新的檔案。
這些案例是由 dwCreationDisposition 參數的適當使用所控制。 以下是這些案例如何對應至此參數的值,以及其使用時會發生什麼情況的細目。
當具有該名稱的檔案不存在時建立或開啟新檔案時(dwCreationDisposition 設定為 CREATE_NEW、 CREATE_ALWAYS 或 OPEN_ALWAYS), CreateFile 函式會執行下列動作:
- 結合dwFlagsAndAttributes 指定的檔案屬性和旗標與FILE_ATTRIBUTE_ARCHIVE。
- 將檔案長度設定為零。
- 如果 指定 hTemplateFile 參數,範本檔案所提供的擴充屬性會複製到新檔案(這會覆寫稍早指定的所有 FILE_ATTRIBUTE_* 旗標)。
- 設定 bInheritHandle 成員所指定的繼承旗標,以及 lpSecurityAttributes 參數的 lpSecurityDescriptor 成員 SECURITY_ATTRIBUTES所指定的安全描述元,如果提供的話。
建立新檔案時,即使相同名稱的檔案已經存在(dwCreationDisposition 設定為 CREATE_ALWAYS), CreateFile 函式仍會執行下列動作:
- 檢查目前的檔案屬性和安全性設定是否有寫入存取權,如果遭到拒絕,就會失敗。
- 結合dwFlagsAndAttributes指定的檔案屬性和旗標,FILE_ATTRIBUTE_ARCHIVE以及現有的檔案屬性。
- 將檔案長度設定為零(也就是說,檔案中的任何數據已不再可用,且檔案是空的)。
- 如果 指定 hTemplateFile 參數,範本檔案所提供的擴充屬性會複製到新檔案(這會覆寫稍早指定的所有 FILE_ATTRIBUTE_* 旗標)。
- 如果提供,則會設定 lpSecurityAttributes 參數 (SECURITY_ATTRIBUTES structure) 之 bInheritHandle 成員所指定的繼承旗標,但忽略SECURITY_ATTRIBUTES結構的 lpSecurityDescriptor 成員。
- 如果成功(也就是CreateFile傳回有效的句柄),即便在這個特定的用例中,其實這並不算是一個錯誤(如果您是打算將現有的檔案替換為一個“新的”(空白)檔案)),呼叫GetLastError仍會顯示ERROR_ALREADY_EXISTS程式碼。
開啟現有的檔案時(dwCreationDisposition 設定為 OPEN_EXISTING、 OPEN_ALWAYS 或 TRUNCATE_EXISTING), CreateFile 函式會執行下列動作:
- 檢查目前的檔案屬性和安全性設定,以取得要求的存取權,如果遭到拒絕,就會失敗。
- 結合 dwFlagsAndAttributes 所指定的檔案旗標 (FILE_FLAG_*) 與現有的檔案屬性,並忽略 dwFlagsAndAttributes 所指定的任何檔案屬性 (FILE_ATTRIBUTE_*)。
- 只有當 dwCreationDisposition 設定為 TRUNCATE_EXISTING 時,才會將檔案長度設定為零,否則會維持目前的檔案長度,並依現狀開啟檔案。
- 忽略 hTemplateFile 參數。
- 如果提供,則會設定 lpSecurityAttributes 參數 (SECURITY_ATTRIBUTES structure) 之 bInheritHandle 成員所指定的繼承旗標,但忽略SECURITY_ATTRIBUTES結構的 lpSecurityDescriptor 成員。
檔案屬性和目錄
檔案屬性是與檔案或目錄相關聯的元數據的一部分,每個元數據都有自己的用途和規則,可如何設定和變更。 其中有些屬性僅適用於檔案,有些則僅適用於目錄。 例如, FILE_ATTRIBUTE_DIRECTORY 屬性僅適用於目錄:檔案系統會使用此屬性來判斷磁碟上的物件是否為目錄,但無法變更現有的文件系統物件。
某些檔案屬性可以針對目錄設定,但只對在該目錄中建立的檔案具有意義,做為默認屬性。 例如, 您可以在目錄對象上設定FILE_ATTRIBUTE_COMPRESSED ,但由於目錄物件本身不包含實際數據,因此不會真正壓縮;不過,以此屬性標示的目錄會告知文件系統壓縮新增至該目錄的任何新檔案。 可在目錄上設定的任何檔案屬性,也會針對新增至該目錄的新檔案設定為 繼承屬性。
CreateFile 函式提供參數,可在建立檔案時設定特定檔案屬性。 一般而言,這些屬性是應用程式在檔案建立時最常使用的屬性,但並非所有可能的檔案屬性都可供 CreateFile 使用。 某些檔案屬性需要使用其他函式,例如 SetFileAttributes、 DeviceIoControl 或 DecryptFile 檔案已經存在之後。 在 FILE_ATTRIBUTE_DIRECTORY的情況下, CreateDirectory 函式在建立時是必要的,因為 CreateFile 無法建立目錄。 需要特殊處理的其他檔案屬性是 FILE_ATTRIBUTE_REPARSE_POINT 和 FILE_ATTRIBUTE_SPARSE_FILE,這需要 DeviceIoControl。 如需詳細資訊,請參閱 SetFileAttributes。
如先前所述,當檔案是以從檔案所在的目錄屬性讀取的檔案屬性建立時,就會發生檔案屬性繼承。 下表摘要說明這些繼承的屬性,以及它們與 CreateFile 功能的關係。
| 目錄屬性狀態 | 新檔案的 CreateFile 權限繼承覆寫功能 |
|---|---|
| FILE_ATTRIBUTE_COMPRESSED 設定。 | 沒有控制 使用 DeviceIoControl 清除。 |
| FILE_ATTRIBUTE_COMPRESSED未設定。 | 沒有控制 使用 DeviceIoControl 來設定。 |
| FILE_ATTRIBUTE_ENCRYPTED 屬性已設定。 | 沒有控制 使用 DecryptFile。 |
| FILE_ATTRIBUTE_ENCRYPTED未設定。 | 可以使用 CreateFile 來設定。 |
| FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 已設置。 | 沒有控制 使用 SetFileAttributes 來清除。 |
| FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 未設定。 | 沒有控制 使用 SetFileAttributes 來設定。 |