建立和開啟檔案

CreateFile函式可以建立新的檔案或開啟現有的檔案。 您必須指定檔案名、建立指示和其他屬性。 當應用程式建立新的檔案時,作業系統會將它新增至指定的目錄。

作業系統會將稱為 控制碼的唯一識別碼指派給使用 CreateFile開啟或建立的每個檔案。 應用程式可以搭配讀取、寫入及描述檔案的函式使用此控制碼。 在關閉該控制碼的所有參考之前都是有效的。 當應用程式啟動時,如果控制碼建立為可繼承,它會從啟動它的進程繼承所有開啟的控制碼。

應用程式應該先檢查 CreateFile 傳回的控制碼值,再嘗試使用控制碼來存取檔案。 如果發生錯誤,控制碼值將會 INVALID_HANDLE_VALUE ,而且應用程式可以使用 GetLastError 函式來取得擴充的錯誤資訊。

當應用程式使用 CreateFile時,必須使用 dwDesiredAccess 參數來指定它是否要從檔案讀取、寫入檔案、讀取和寫入,或兩者皆否。 這稱為要求 存取模式。 應用程式也必須使用 dwCreationDisposition 參數來指定檔案已經存在時要採取的動作,稱為 建立處置。 例如,應用程式可以呼叫CreateFile,並將 dwCreationDisposition設定為CREATE_ALWAYS一律建立新的檔案,即使同名的檔案已經存在 (因此覆寫現有的檔案) 。 這是否成功取決於先前檔案的屬性和安全性設定等因素, (請參閱下列各節以取得詳細資訊) 。

應用程式也會使用 CreateFile 來指定它是否要共用檔案以供讀取、寫入、兩者或兩者皆未共用。 這稱為 共用模式。 (dwShareMode 未共用的開啟檔案設定為零,) 無法再次由開啟它的應用程式或其他應用程式開啟,直到其控制碼關閉為止。 這也稱為獨佔存取。

當進程使用 CreateFile 嘗試開啟已在共用模式中開啟的檔案, (dwShareMode 設定為有效的非零值) 時,系統會將要求的存取和共用模式與開啟檔案時所指定的檔案進行比較。 如果您指定與上一次呼叫中指定的模式衝突的存取或共用模式, CreateFile 會失敗。

下表說明使用各種存取模式以及dwDesiredAccessdwShareMode分別) 各種存取模式和共用 (模式來呼叫CreateFile的有效組合。 建立 CreateFile 呼叫的順序並不重要。 不過,每個檔案控制代碼上任何後續的檔案 I/O 作業仍受限於與該特定檔案控制碼相關聯的目前存取和共用模式。

第一次呼叫CreateFile 對 CreateFile的有效第二次呼叫
GENERIC_READFILE_SHARE_READ
  • GENERIC_READFILE_SHARE_READ
  • GENERIC_READFILE_SHARE_READFILE_SHARE_WRITE
GENERIC_READFILE_SHARE_WRITE
  • GENERIC_WRITEFILE_SHARE_READ
  • GENERIC_WRITEFILE_SHARE_READFILE_SHARE_WRITE
GENERIC_READFILE_SHARE_READ FILE_SHARE_WRITE
  • GENERIC_READFILE_SHARE_READ
  • GENERIC_READFILE_SHARE_READFILE_SHARE_WRITE
  • GENERIC_WRITEFILE_SHARE_READ
  • GENERIC_WRITEFILE_SHARE_READFILE_SHARE_WRITE
  • GENERIC_READGENERIC_WRITEFILE_SHARE_READ
  • GENERIC_READGENERIC_WRITEFILE_SHARE_READFILE_SHARE_WRITE
GENERIC_WRITEFILE_SHARE_READ
  • GENERIC_READFILE_SHARE_WRITE
  • GENERIC_READFILE_SHARE_READFILE_SHARE_WRITE
GENERIC_WRITEFILE_SHARE_WRITE
  • GENERIC_WRITEFILE_SHARE_WRITE
  • GENERIC_WRITEFILE_SHARE_READFILE_SHARE_WRITE
GENERIC_WRITEFILE_SHARE_READ FILE_SHARE_WRITE
  • GENERIC_READFILE_SHARE_WRITE
  • GENERIC_READFILE_SHARE_READFILE_SHARE_WRITE
  • GENERIC_WRITEFILE_SHARE_WRITE
  • GENERIC_WRITEFILE_SHARE_READFILE_SHARE_WRITE
  • GENERIC_READGENERIC_WRITEFILE_SHARE_WRITE
  • GENERIC_READGENERIC_WRITEFILE_SHARE_READFILE_SHARE_WRITE
GENERIC_READGENERIC_WRITEFILE_SHARE_READ
  • GENERIC_READFILE_SHARE_READFILE_SHARE_WRITE
GENERIC_READGENERIC_WRITEFILE_SHARE_WRITE
  • GENERIC_WRITEFILE_SHARE_READFILE_SHARE_WRITE
GENERIC_READGENERIC_WRITEFILE_SHARE_READFILE_SHARE_WRITE
  • GENERIC_READFILE_SHARE_READFILE_SHARE_WRITE
  • GENERIC_WRITEFILE_SHARE_READFILE_SHARE_WRITE
  • GENERIC_READGENERIC_WRITEFILE_SHARE_READFILE_SHARE_WRITE

除了標準檔案屬性之外,您也可以將 SECURITY_ATTRIBUTES 結構的指標納入為 CreateFile的第四個參數,以指定安全性屬性。 不過,基礎檔案系統必須支援安全性 (,如此一來,例如,NTFS 檔案系統支援它,但各種 FAT 檔案系統不會) 。 如需安全性屬性的詳細資訊,請參閱存取控制

建立新檔案的應用程式可以提供範本檔案的選擇性控制碼, 而 CreateFile 會從中取得檔案屬性和擴充屬性以建立新檔案。

CreateFile 案例

有數個基本案例可使用 CreateFile 函式起始檔案的存取權。 這些摘要如下:

  • 當具有該名稱的檔案不存在時,建立新的檔案。
  • 建立新檔案,即使同名的檔案已經存在,清除其資料並啟動空白。
  • 只有在現有檔案存在時,才開啟現有的檔案,而且只會保持不變。
  • 只有在現有檔案存在時,才開啟現有的檔案,將其截斷為空白。
  • 一律開啟檔案:如果檔案存在,請建立不存在的新檔案。

這些案例是由 dwCreationDisposition 參數的適當使用所控制。 以下是這些案例如何對應至此參數的值,以及使用時會發生什麼情況的明細。

當具有該名稱的檔案不存在 (dwCreationDisposition 設定為 CREATE_NEWCREATE_ALWAYSOPEN_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參數的 bInheritHandle成員所指定的繼承旗標, (SECURITY_ATTRIBUTES結構) 提供,但會忽略SECURITY_ATTRIBUTES結構的lpSecurityDescriptor成員。
  • 如果否則成功 (, CreateFile 會傳回有效的控制碼) ,呼叫 GetLastError 就會產生 程式碼ERROR_ALREADY_EXISTS,即使針對這個特定使用案例,它實際上不是錯誤, (例如,如果您打算建立「新」 (空的) 檔案取代現有的) 。

開啟現有檔案 (dwCreationDisposition 設為 OPEN_EXISTINGOPEN_ALWAYSTRUNCATE_EXISTING) 時, CreateFile 函式會執行下列動作:

  • 檢查目前檔案屬性和安全性設定是否有要求的存取權,如果遭到拒絕,則失敗。
  • 結合dwFlagsAndAttributes所指定的檔案旗標 (FILE_FLAG_*) ,並忽略dwFlagsAndAttributes所指定 (FILE_ATTRIBUTE_*) 的任何檔案屬性。
  • 只有當 dwCreationDisposition 設定為 TRUNCATE_EXISTING時,才會將檔案長度設定為零,否則會維持目前的檔案長度,並以原狀方式開啟檔案。
  • 忽略 hTemplateFile 參數。
  • 設定由lpSecurityAttributes參數的 bInheritHandle成員所指定的繼承旗標, (SECURITY_ATTRIBUTES結構) 提供,但會忽略SECURITY_ATTRIBUTES結構的lpSecurityDescriptor成員。

檔案屬性和目錄

檔案屬性是與檔案或目錄相關聯的中繼資料的一部分,每個中繼資料都有自己的用途和規則,以瞭解如何設定和變更。 其中有些屬性僅適用于檔案,有些則僅適用于目錄。 例如, FILE_ATTRIBUTE_DIRECTORY 屬性僅適用于目錄:檔案系統會使用它來判斷磁片上的物件是否為目錄,但無法變更現有的檔案系統物件。

您可以為目錄設定某些檔案屬性,但只對在該目錄中建立的檔案有意義,做為預設屬性。 例如, FILE_ATTRIBUTE_COMPRESSED 可以在目錄物件上設定,但因為目錄物件本身不包含實際資料,所以不會真正壓縮;不過,標示為此屬性的目錄會告知檔案系統壓縮新增至該目錄的任何新檔案。 任何可在目錄上設定的檔案屬性,也會針對新增至該目錄的新檔案設定為 繼承屬性

CreateFile函式會提供參數,以在建立檔案時設定特定檔案屬性。 一般而言,這些屬性是應用程式在檔案建立時最常使用的屬性,但並非所有可能的檔案屬性都可供 CreateFile使用。 某些檔案屬性需要使用其他函式,例如 SetFileAttributesDeviceIoControlDecryptFile ,檔案已經存在。 在 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 來設定。

存取控制

CreateFile

DeviceIoControl

檔案屬性常數

檔案壓縮和解壓縮

檔案加密

檔案管理功能

控制碼和物件

處理繼承

開啟檔案進行讀取或寫入

SetFileAttributes