建立和開啟檔案
CreateFile 函式可以建立新的檔案或開啟現有的檔案。 您必須指定檔名、建立指示和其他屬性。 當應用程式建立新的檔案時,作業系統會將它新增至指定的目錄。
操作系統會將稱為句柄的唯一標識符指派給使用 CreateFile 開啟或建立的每個檔案。 應用程式可以使用這個句柄搭配讀取、寫入和描述檔案的函式。 在關閉該句柄的所有參考之前,它是有效的。 當應用程式啟動時,它會從啟動它的進程繼承所有開啟的句柄,如果句柄建立為可繼承。
應用程式應該先檢查 CreateFile 傳回的句柄值,再嘗試使用句柄來存取檔案。 如果發生錯誤,句柄值將會INVALID_HANDLE_VALUE,而且應用程式可以使用 GetLastError 函式來取得延伸的錯誤資訊。
當應用程式使用 CreateFile 時,它必須使用 dwDesiredAccess 參數來指定它是否打算從檔案讀取、寫入檔案、讀取和寫入,或兩者都不是。 這稱為要求 存取模式。 應用程式也必須使用 dwCreationDisposition 參數來指定檔案已經存在時要採取的動作,稱為 建立處置。 例如,應用程式可以呼叫 createFile ,並將 dwCreationDisposition 設定為 CREATE_ALWAYS ,以一律建立新的檔案,即使已有相同名稱的檔案存在(因此會覆寫現有的檔案)。 這是否成功取決於上一個檔案的屬性和安全性設定等因素(如需詳細資訊,請參閱下列各節)。
應用程式也會使用 CreateFile 來指定它是否要共用檔案以供讀取、寫入或兩者皆否。 這稱為 共用模式。 未共享的開啟檔案(dwShareMode 設定為零)無法再次由開啟它或由另一個應用程式開啟,直到其句柄關閉為止。 這也稱為獨佔存取權。
當進程使用 CreateFile 嘗試開啟已以共用模式開啟的檔案時(dwShareMode 設定為有效的非零值),系統會比較要求的存取和共用模式與開啟檔案時所指定的檔案。 如果您指定與上一個呼叫中指定的模式衝突的存取或共用模式, CreateFile 會失敗。
下表說明兩個呼叫 CreateFile 的有效組合,分別使用各種存取模式和共用模式(dwDesiredAccess、dwShareMode)。 建立File 呼叫的順序並不重要。 不過,每個檔句柄上任何後續的檔案 I/O 作業仍會受到與該特定檔句柄相關聯的目前存取和共用模式所限制。
第一次呼叫 CreateFile | CreateFile 的有效第二次呼叫 |
---|---|
GENERIC_READ,FILE_SHARE_READ |
|
GENERIC_READ,FILE_SHARE_WRITE |
|
GENERIC_READ、 FILE_SHARE_READ、 FILE_SHARE_WRITE |
|
GENERIC_WRITE,FILE_SHARE_READ |
|
GENERIC_WRITE,FILE_SHARE_WRITE |
|
GENERIC_WRITE、 FILE_SHARE_READ、 FILE_SHARE_WRITE |
|
GENERIC_READ、GENERIC_WRITE、FILE_SHARE_READ |
|
GENERIC_READ、 GENERIC_WRITE、 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,即使針對這個特定的使用案例,它實際上不是錯誤,例如(如果您打算建立“new” (空白) 檔案來取代現有的檔案)。
開啟現有的檔案時(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 來設定。 |