Evernote Export
CreateFile中文翻譯
這次的課程最重要的就是教了如果去學習MSDN上面的函數,和哪些是重點
//本課程老師主要講解了如果從MSDN學習函數的方法 //函數一般分為 函數名稱 函數說明 函數參數 函數參數調用方法 函數的返回值 是否成功是否失敗 Return value 函數調用的例子 Examples 擴展閱讀和備注
//如果遇到不懂的英文可以用有道詞典 進行實時翻譯
函數的 A版本 和 W版本
A版本為 窄字符集 ASCII
W版本為 寬字符集 UNICODE
對應的字符串 窄字符集 char
對應的字符串 寬字符集 wchar_t
微軟內置變量 TCHAR 根據是否設置UNICDOE 和 ASCII 進行自動切換一般不要使用這種模式,很容易混淆
函數功能
CreateFile 函數用於創建或打開一個文件或者 I/O 設備。最常使用的 I/O 設備如下:
- 文件
- 文件流
- 文件夾
- 物理磁盤
- 邏輯磁盤驅動器
- 控制台程序緩沖區
- 磁帶
- 通信資源
- 郵槽
- 管道
此函數返回一個指向用於訪問來自不同類型I/O的文件或設備的句柄,其訪問權限取決於它所訪問的文件、設備和我們所指定的標記位、屬性。
為了使之可以處理事務型 I/O,請使用 CreateFileTransacted 函數。
API 函數原型
1.HANDLE WINAPI CreateFile(
2. _In_ LPCTSTR lpFileName, lp 代表指針 filename 文件名
3. _In_ DWORD dwDesiredAccess, dw unsigned long 訪問權限
4. _In_ DWORD dwShareMode, 設備共享模式
5. _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, 結構體指針
6. _In_ DWORD dwCreationDisposition,
7. _In_ DWORD dwFlagsAndAttributes,
8. _In_opt_ HANDLE hTemplateFile
9.);
//__in:輸入參數; __out:輸出參數 ;__in_opt:輸入指針型的參數
//如果參數 __out 注意 必須保證字符串是有足夠空間的
參數解析
lpFileName
指定要打開、創建的文件或設備的名字。你可以在名字中使用斜杠(/)或者反斜杠(\)
在此函數的 ANSI 版本中,名字長度被限制為 MAX_PATH 個字符。為了將此限制擴展到 32767 個寬字符,需要調用此函數的 Unicode 版本,並且在添加在路徑名中添加 “\?\” 前綴。獲取更多的信息,參見 Naming Files, Paths, and Namespaces
想獲取關於特殊設備的名字,參見 Defining an MS-DOS Device Name
為了創建一個文件流,需要指定文件名,一個冒號加上流文件的名字。獲取更多信息,參見 File Streams
dwDesiredAccess
指定以何種權限打開文件或設備,可以歸納為:讀訪問權、寫訪問權、讀寫訪問權、非讀非寫訪問權
最常使用的值為 GENERIC_READ, GENERIC_WRITE, 或者二者都用(GENERIC_READ | GENERIC_WRITE)。獲取更多信息,參見 Generic Access Rights, File Security and Access Rights, File Access Rights Constants 和 ACCESS_MASK
如果參數值為 0,那么程序可以在不訪問文件或設備情況下,詢問某些元數據,如文件、目錄或者設備屬性。此外,即使 GENERIC_READ 請求,也會被拒絕
你無法請求一個與共享模式沖突的訪問權限。共享模式是在參數 dwShareMode 中設置的
獲取更多信息,參見本文備注以及 Creating and Opening Files
dwShareMode
設置文件或者設備的共享模式,包括讀、寫、讀寫、刪除、全部權限或者以上什么權限都沒有(參考下面的表格)。此參數不影響對屬性和擴展屬性的訪問請求
如果此參數為 0 且 CreateFile 函數執行成功,那么此文件或設備無法被共享,且在其句柄被關閉前,無法被再次打開。更多信息,參見本文備注。
你無法設置一個與訪問模式相沖突的共享模式。此時如果 CreateFile 函數執行失敗,那么 GetLastError 函數會返回 ERROR_SHARING_VIOLATION
為了允許進程去共享一個已經在另一個進程中打開的文件或句柄,那么可對以下一個或多個取值進行組合,且各取值間需要可互相兼容。更多有關此參數與 dwDesiredAccess 參數的合法取值組合的信息,參見 Creating and Opening Files
注意:在句柄被關閉之前,每個句柄的共享選項都會一直生效,且與進程的運行上下文(process context)無關。
值 含義 0 防止其他進程以刪除、讀取或寫入權限打開一個文件或者設備 FILE_SHARE_DELETE(0x00000004) 1.允許隨后的對文件或設備的打開操作獲取刪除權限
2.否則,其他進程無法以刪除權限打開一個文件或設備
3.如果此標記位沒有指定,但文件或設備已經打開並且獲取了刪除權限,則此函數執行失敗
4.注意:刪除權限運行刪除操作和重命名操作FILE_SHARE_READ(0x00000001) 1.允許后續對文件或設備的讀權限打開請求
2.否則,其他進程無法以讀權限打開此文件
3.如果此處標記位未被指定,但是文件或設備被以讀權限打開,則函數執行失敗FILE_SHARE_WRITE(0x00000002) 1.允許后續對文件或設備的寫權限打開請求
lpSecurityAttributes
指向 SECURITY_ATTRIBUTES 結構體的指針。此結構體擁有兩個分開但是相關的數據成員:一個是可選的安全描述符,另一個是決定返回的句柄是否可以被子進程繼承的 Boolean 值
此參數可以設置為 NULL
如果參數為 NULL,那么 CreateFile 函數返回的句柄無法被任意此進程的子進程所繼承,且與返回的句柄所對應的文件或句柄擁有一個默認的安全描述符
該結構體的 lpSecurityDescriptor 成員為文件或設備指定一個安全描述符(SECURITY_DESCRIPTOR)。如果此成員取值為 NULL,那么與返回的句柄所對應的文件或句柄擁有一個默認的安全描述符
當打開一個已經存在的文件或設備時,CreateFile 函數忽略 lpSecurityDescriptor 成員,但是 bInheritHandle 成員仍然可以使用
結構體的 bInheritHandle 成員用於設置返回的句柄是否可以被繼承
更多信息,參見本文備注
dwCreationDisposition
用於設置當文件存在或不存在時,要對文件或設備執行何種操作
對於設備來說,此參數通常設置為 OPEN_EXISTING
更多信息,參見本文備注
這個參數的值必須為以下值之一,且只能選擇一個而不能組合多個:
值 含義 CREATE_ALWAYS 1.總是創建一個新文件
2.如果指定的文件已經存在而且是可寫的,此時函數重寫(overwrite)這個文件,函數為執行成功、且將 last-error code 設置為 ERROR_ALREADY_EXISTS(183)
3.如果指定的文件不存在且其路徑名合法,那么會創建一個新文件,函數為執行成功、且將 last-error code 設為 0
4. 更多信息,參見本文備注CREATE_NEW 1.僅當文件不存在時,才創建一個新文件
2.如果指定文件已存在,函數執行失敗且將 last-error code 設為 ERROR_FILE_EXISTS(80)
3.如果指定文件不存在,當路徑名合法而且可寫時,則創建一個新文件OPEN_ALWAYS 1.總是打開一個文件
2.如果指定的文件存在,函數執行成功,且 last-error code 設置為 ERROR_ALREADY_EXISTS(183)
3.如果指定文件不存在,當路徑名合法而且可寫時,則創建一個新文件,last-error code 設置為 0OPEN_EXISTING 1.僅當文件或設備存在時,才打開它
2.如果指定的文件或設備不存在,函數執行失敗且 last-error code 設置為 ERROR_FILE_NOT_FOUND(2)3.更多信息,參見本文備注TRUNCATE_EXISTING 1.僅當文件存在時,才打開一個文件並且將其大小截取到 0 字節
2.如果指定的文件不存在,函數執行失敗且 last-error code 設置為 ERROR_FILE_NOT_FOUND(2)
3.調用方需要設置 dwDesiredAccess 參數的 GENERIC_WRITE 位
dwFlagsAndAttributes
文件或設備的屬性值和標記位,對於文件來說,FILE_ATTRIBUTE_NORMAL 是最常用的默認值
此參數可以是任意文件屬性值(FILE_ATTRIBUTE_*)的組合。所有其他的文件屬性值會覆蓋 FILE_ATTRIBUTE_NORMAL
此參數也可以包含任意標記位(FILE_FLAG_*)的組合以控制文件或設備的行為、權限設置和其他目的。此外,還可以與任意 FILE_ATTRIBUTE_* 進行組合
這個參數還可以通過指定 SECURITY_SQOS_PRESENT 標記來包含 Security Quality of Service (SQOS) 信息。與SQOS相關的標記位信息見屬性與標記位表格下面的表格中
注意:當CreateFile 打開一個已存在的文件時,它通常將文件屬性和文件標記位組合在一起,並且忽略在 dwFlagsAndAttributes 中定義的屬性值。詳細例子見 Creating and Opening Files
以下的屬性和標記位可能只適用於文件的打開,而並非支持所有其他 CreateFile 函數可以打開的設備。想了解更多信息,參見本文備注部分和 Creating and Opening Files。想進一步了解文件屬性相關信息,參見 SetFileAttributes 函數。你還可以在 File Attribute Constants 中看到完整的介紹所有文件屬性的值和對應描述信息
屬性 含義 FILE_ATTRIBUTE_ARCHIVE 文件應該被存檔。應用程序使用此屬性來備份或移除標記文件 FILE_ATTRIBUTE_ENCRYPTED 1.文件或目錄被加密。對於文件來說,這意味着文件中所有數據都被加密了;對於目錄來說,這意味着加密新創建的文件和子文件夾是默認選項。更多信息,參見 File Encryption
2.如果指定了FILE_ATTRIBUTE_SYSTEM標記位,則這個標記位不起作用
3.這個標記位在以下 Windows 版本中不被支持:家庭版、家庭高級版、簡易版或 ARM 版本FILE_ATTRIBUTE_HIDDEN 文件被隱藏。即在普通文件夾中不被顯示 FILE_ATTRIBUTE_NORMAL 這個文件不包含其他屬性。只有當它單獨使用時,這個屬性值才是合法的 FILE_ATTRIBUTE_OFFLINE 文件的數據無法直接訪問。這個屬性表示文件數據在物理設備中被移動到一個離線存儲器。這個屬性被遠程存儲(Remote Storage)—— 即分級存儲管理軟件 —— 所使用。我們的程序不能隨意改變這個屬性值 FILE_ATTRIBUTE_READONLY 文件只讀。程序可以讀取文件,但無法寫入或刪除文件 FILE_ATTRIBUTE_SYSTEM 文件是操作系統的的一部分或者專門為操作系統所使用 FILE_ATTRIBUTE_TEMPORARY 1.文件用於存儲臨時數據
2.更多信息,參見 Caching BehaviorFILE_FLAG_BACKUP_SEMANTICS 1.此文件已經被打開或者創建以用於備份或者恢復操作。當調用進程擁有 SE_BACKUP_NAME 和 SE_RESTORE_NAME 權限時,系統保證調用進程覆蓋文件安全檢測。更多信息,參見 Changing Privileges in a Token
2.為了獲取一個文件夾句柄,你必須設置這個標記位。某些函數只能接受文件夾句柄而非文件句柄。更多信息,參見本文備注FILE_FLAG_DELETE_ON_CLOSE 1.在所有與此文件相關的句柄被關閉后,文件馬上會被刪除。與此文件相關的句柄包括當前句柄和任意其他打開或者被復制的句柄
2.如果存在指向文件的句柄,且所有這些句柄是以 FILE_SHARE_DELETE 共享模式創建,則函數執行失敗。如果沒有指定 FILE_SHARE_DELETE 共享模式,文件后續的打開請求都會失敗FILE_FLAG_NO_BUFFERING 1.文件或設備被以讀寫無緩沖區的方式打開。此標記位對於硬盤或者內存映射文件無效。
2.此外,若想讓 FILE_FLAG_NO_BUFFERING 標記位正常工作,還需要滿足一些嚴格的要求,具體參見 File BufferingFILE_FLAG_OPEN_NO_RECALL 文件數據被請求,但它不應該繼續在遠程存儲器中被定位。文件數據不應該傳輸回本地存儲器。這個標記位被遠程存儲系統所使用 FILE_FLAG_OPEN_REPARSE_POINT 1.不會發生正常的 reparse point 過程。 CreateFile 函數將會嘗試去打開一個 reparse point。當一個文件被打開,無論控制 reparse point 的過濾器是否可操作,都會返回一個文件句柄
2.此標記無法與 CREATE_ALWAYS 標記位共同使用
3.如果文件不是一個 reparse point,那么此標記位無效
4.更多信息,參見本文備注FILE_FLAG_OVERLAPPED 1.此文件或設備被打開或創建,用於異步 I/O
2.當后續的 I/O 操作通過此句柄執行完成,則 OVERLAPPED 結構中指定的事件會被設置為受信狀態
3.如果此標記位被指定,此文件可以被用於同步讀寫操作
4.如果此標記為未被指定,則 I/O 操作被序列化,即使對讀寫函數的調用指定了一個 OVERLAPPED 結構
5.更多關於使用一個指定了此標記位的文件句柄的信息,參見本頁 Synchronous and Asynchronous I/O Handles 章節FILE_FLAG_POSIX_SEMANTICS 遵循 POSIX 規則,這包括允許多個文件名,只是在不同的情況下,為支持該命名規則的文件系統。當使用此選項時要小心,因為一個使用此標記位創建的文件可能無法被某些為 MS-DOS 或 16 位 Windows 操作系統所編寫的程序所訪問 FILE_FLAG_RANDOM_ACCESS 1.文件訪問為隨機訪問。此系統可以使用這個用於優化文件緩存
2.如果文件系統不支持 I/O 緩沖和 FILE_FLAG_NO_BUFFERING 標記,則此標記位無效
3.更多信息,參見 Caching BehaviorFILE_FLAG_SESSION_AWARE 1.文件或設備帶 session awareness 打開。如果此標記位沒有被指定,則 per-session 設備(一個使用 RemoteFX USB 重定向的設備)無法被運行在 session 0 的進程所打開。如果調用進程沒有運行在 session 0,則此標記位無效。此標記位只支持在 server 版本的 Windows
2.indows Server 2008 R2 和 Windows Server 2008:此標記位不支持 Windows Server 2012 之前的版本FILE_FLAG_SEQUENTIAL_SCAN 1.表示文件訪問將從頭順序讀到尾。系統利用此標記位用於優化文件緩存
2.如果你打算從文件尾讀到文件頭(即反向掃描文件),則不該使用此標記位
3.如果文件系統不支持 I/O 緩存和 FILE_FLAG_NO_BUFFERING 標記位,則此標記位無效
4.更多信息,參見 Caching BehaviorFILE_FLAG_WRITE_THROUGH 1.寫操作不會通過任何中間緩沖區緩沖,而是直接寫回磁盤
2.更多信息,參見 Caching Behavior
3. wFlagsAndAttributes 參數還可以指定 SQOS 信息。更多信息,參見 Impersonation Levels。當程序在 dwFlagsAndAttribbutes 指定了 SECURITY_SQOS_PRESENT 標記位,它還可以包含下表一個或多個值:
SECURITY_ANONYMOUS 將客戶端模擬在匿名級別
SECURITY_CONTEXT_TRACKING 指定安全跟蹤模式是動態的。 如果此標記位未被指定,則安全跟蹤模式為靜態的
SECURITY_DELEGATION 將客戶端模擬在授權級別
SECURITY_EFFECTIVE_ONLY服務器只能訪問到客戶端安全配置中被允許的數據。如果此標記位未被指定,則客戶端安全配置中所有數據都能訪問;當模擬一個客戶端時,此標記位允許客戶端去限制服務端可以使用的組和權限
SECURITY_IDENTIFICATION 將客戶端模擬在身份認證級別
SECURITY_IMPERSONATION將客戶端模擬在偽裝級別;如果沒有其他標記位和
SECURITY_SQOS_PRESENT 標記位共同被指定,則當前標記位是默認標記
hTemplateFile
指向一個擁有 GENERIC_READ 訪問權限的的模板文件的合法句柄
此模板文件為即將創建的文件提供屬性和擴展屬性
參數值可以為 NULL
如果打開一個已存在的文件,則 CreateFile 函數忽略這個參數
如果打開一個新的被加密文件,此函數從其父目錄中繼承自由存取控制列表。更多信息,見 File Encryption
返回值
如果函數調用成功,返回指向指定文件的句柄、設備、命名管道或者郵槽;
如果函數調用失敗,返回值為 INVALID_HANDLE_VALUE。
想獲取具體錯誤信息,調用 GetLastError 函數。
備注
-
CreateFile 函數最初被官方開發用於文件操作,但后來功能被擴展加強,Windows 開發者可用它來處理絕大部分其他類型的 I/O 設備和機器。當前備注試圖講解開發者在不同的環境下使用不同的 I/O 設備過程中,調用 CreateFile 函數可能遇到的不同的問題。
這篇文章中,僅當數據是存儲在一個文件系統上的真正的文件,才會使用”文件”這個詞。然而,在提及“文件”的情況下,有一些只得是更廣義上的 I/O 對象,這些 I/O 對象支持類似文件操作的機制。由於前面所提及到的歷史原因,“文件”這個名詞使用過於自由,已經廣泛被各種常量名稱和參數名稱所使用。 -
當 CreateFile 函數返回的句柄不再使用時,調用 CloseHandle 函數關閉這個句柄。這不僅只是釋放系統資源,對於如文件或設備的共享和磁盤的數據提交等仍有很大的影響。具體細節在本文描述有介紹。
-
Windows Server 2003 and Windows XP:當我們試圖打開一個遠程文件或目錄以用於刪除,此時如果指定了 dwDesiredAccess 參數包含了刪除標記(0x00010000),且遠程文件或目錄並未以 FILE_SHARE_DELETE 屬性被打開,那么就會引發共享錯誤。在這個例子中,為了避免共享錯誤發生,僅且僅以刪除權限打開遠程文件或目錄,或者不用打開文件而是直接調用 DeleteFile 函數去刪除文件。
-
一些文件系統,如 NTFS 文件系統,支持某些文件和文件夾的壓縮和加密。如果一個分區裝載了支持這些功能的文件系統,則一個新文件會從它所屬文件夾中繼承這些壓縮和加密的屬性。
-
你無法使用 CreateFile 函數去控制文件的壓縮、解壓或加密。更多信息,參見 Creating and Opening Files, File Compression and Decompression 和 File Encryption。
-
Windows Server 2003 and Windows XP:為了實現向后兼容,當你在 lpSecurityAttributes 參數中指定一個安全描述符時,CreateFile 函數並不會應用繼承規則。為了支持繼承,后續詢問文件安全描述符的函數可能會啟發式地去決定並告知繼承已經生效了。更多信息,參見 Automatic Propagation of Inheritable ACEs。
- 正如前面所闡述的,如果 lpSecurityAttributes 參數為 NULL,則 CreateFile 函數返回的句柄無法被你的程序可能創建的任何子進程所繼承。以下是關於此參數被應用的信息:
如果 bInheritHandle 成員的取值不是 FALSE,而是其他任意非 0 值,那么這個句柄可以被繼承。因此如果你不希望此句柄可以被繼承,注意要把此參數初始化為 FALSE
文件或目錄默認安全描述符中的訪問控制列表(ACL)繼承自其父目錄
若想使 lpSecurityDescriptor 成員對文件和目錄有效,文件系統必須支持文件和目錄安全,這由使用 GetVolumeInformation 函數決定
在 Windows 8 和 Windows Server 2012 中,此函數由以下技術支持:
技術 | 是否支持 |
---|---|
Server Message Block (SMB) 3.0 protocol | 支持 |
SMB 3.0 Transparent Failover (TFO) | 參見備注 |
SMB 3.0 with Scale-out File Shares (SO) | 參見備注 |
Cluster Shared Volume File System (CsvFS) | 支持 |
Resilient File System (ReFS) | 支持 |
注意:當 CreateFile函數設置將會替代舊文件,如果所處理的文件已經打開了一個數據流,則函數會執行失敗
- 符號鏈接相關
如果此函數的調用產生了一個新文件,FILE_FLAG_OPEN_REPARSE_POINT 標記位被忽視,否則,考慮以下說明:
如果指定了 FILE_FLAG_OPEN_REPARSE_POINT 標記,則:
如果一個已存在的文件被打開且它是一個符號鏈接,則返回的句柄為一個執行符號鏈接的句柄
如果指定了 TRUNCATE_EXISTING 或 FILE_FLAG_DELETE_ON_CLOSE 標記,則被影響的文件是一個符號鏈接
如果未指定了 FILE_FLAG_OPEN_REPARSE_POINT 標記,則:
如果一個已存在的文件被打開且它是一個符號鏈接,則返回的句柄為指向這個目標的句柄
如果指定了 CREATE_ALWAYS, TRUNCATE_EXISTING 或 FILE_FLAG_DELETE_ON_CLOSE 標記,被影響的文件為目標文件 - 文件緩存
CreateFile 函數的 dwFlagsAndAttributes 參數的一些取值,用於告知系統如何指定其返回的文件句柄的緩存模式。這些取值是:
FILE_FLAG_NO_BUFFERING
FILE_FLAG_RANDOM_ACCESS
FILE_FLAG_SEQUENTIAL_SCAN
FILE_FLAG_WRITE_THROUGH
FILE_ATTRIBUTE_TEMPORARY
如果以上標記位都沒有被指定,則系統使用一個默認的適用於大多數情況的緩存模式。否則,系統就會按照我們指定的標記位的模式,進行數據緩存。
某些標記位無法被組合。如組合 FILE_FLAG_RANDOM_ACCESS 標記位和 FILE_FLAG_SEQUENTIAL_SCAN 標記位將發生自我矛盾。
當順序讀取大文件,指定 FILE_FLAG_SEQUENTIAL_SCAN 標記位可以提高性能;當程序讀取大文件時,大部分都是順序讀取,偶爾跳過小范圍的字節數,則性能提高更明顯。如果程序操作文件指針以用於隨機訪問,則大部分情況下是無法達到最優緩存效果的。然而,仍然可以保證操作的正確執行。
FILE_FLAG_WRITE_THROUGH 標記位和 FILE_FLAG_NO_BUFFERING 標記位是獨立的,可以進行組合。
如果指定了 FILE_FLAG_WRITE_THROUGH 標記位,但是沒有指定 FILE_FLAG_NO_BUFFERING 標記位,此時系統緩存機制仍在運行:數據被寫到系統緩存區,但是馬上被寫回磁盤。
如果 FILE_FLAG_WRITE_THROUGH 標記位和 FILE_FLAG_NO_BUFFERING 標記位都被指定了,則系統緩沖區不會起作用,數據不經過 Windows 系統緩存區而是直接寫入磁盤。系統會申請直接寫入到本地磁盤的緩存中。
如果 FILE_FLAG_WRITE_THROUGH 標記位和 FILE_FLAG_NO_BUFFERING 標記位都被指定了,則系統緩存機制停止工作,數據不經過Windows系統緩存去,而是被直接寫到磁盤上。系統會申請直接寫入到本地磁盤的緩存中。
注意:並非所有磁盤硬件都支持直接寫入的方法。
要想正確使用 FILE_FLAG_NO_BUFFERING 標記位,需要對程序一些更深的理解。更多信息,參見 File Buffering。
處理一個直接寫入請求請求(通過 FILE_FLAG_WRITE_THROUGH 標志位來實現)時,會使得 NTFS 刷新任何被修改的元數據,如文件修改時間和重命名操作。為此,FILE_FLAG_WRITE_THROUGH 標記位常和 FILE_FLAG_NO_BUFFERING 標記位共同使用,以替代每次進行寫操作后都調用 FlushFileBuffers 函數將數據寫入文件,而后者會引起不必要的開銷。使用這些標記位可以避免此類不必要的開銷。更多關於文件和元數據緩存的信息,參見 File Caching。
當 FILE_FLAG_NO_BUFFERING 標記位和 FILE_FLAG_OVERLAPPED 標記位共同使用時,可以提供最大化異步 I/O 的效率,因為 I/O 操作並不依賴於內存管理器的同步操作。然而,一些 I/O 操作消耗更多時間,因為沒有使用緩存區。此外,文件元數據可能仍然使用緩存(例如,當創建一個空文件)。為了保證元數據被寫入磁盤,要使用 FlushFileBuffers 函數。
當指定了 FILE_ATTRIBUTE_TEMPORARY 屬性值時,如果有可用的高效的緩沖內存,那么文件系統會避免將數據寫回大容量存儲器,因為程序在文件句柄被關閉后會刪除臨時文件。在這個情況下,系統可以完全避免將數據寫回磁盤。雖然它不像前面提及到的標記位那樣直接控制數據緩存行為,但是 FILE_ATTRIBUTE_TEMPORARY 屬性值會告訴系統盡可能地不要將數據寫到磁盤中,因此這可能會對某些程序很有意義。
- 文件
如果你重命名或刪除一個文件,然后又馬上恢復原樣,則系統會搜索緩存區中的文件信息去執行恢復操作。被緩存的信息包括短、長文件名和文件創建時間。
操作系統會延遲刪除操作、直到所有指向此文件的句柄被關閉。如果某個文件正在等待被執行 DeleteFile 函數,此時對此文件調用 CreateFile 函數,則 CreateFile 函數執行失敗。GetLastError 函數會返回 ERROR_ACCESS_DENIED。
dwDesiredAccess 參數可以為 0,此時如果程序的權限足夠,則系統允許程序不訪問文件而直接獲取文件的屬性值。 這在以下情況是很有用的:當我們不以讀訪問或寫訪問打開一個文件,卻想測試一個文件是否存在或者獲得其他關於此文件或目錄的數據。參見 Obtaining and Setting File Information 和 GetFileInformationByHandle 函數。
如果指定了 CREATE_ALWAYS 和 FILE_ATTRIBUTE_NORMAL,則當文件存在且擁有 FILE_ATTRIBUTE_HIDDEN 屬性值或 FILE_ATTRIBUTE_SYSTEM 屬性值時,CreateFile 函數執行失敗,且 last error 被設置為 ERROR_ACCESS_DENIED。為了避免這個錯誤,要為已存在文件設置與之相同的屬性值。
當程序通過網絡創建一個文件,dwDesiredAccess 參數設置為 GENERIC_READ | GENERIC_WRITE 會比單獨設置 GENERIC_WRITE 要好。這樣會使得代碼執行的更快,因為重定向器可以使用緩存管理器,在發送更多數據的同時,附帶更少的 SMB。二者組合用還可以防止通過網絡寫文件時,偶爾出現ERROR_ACCESS_DENIED錯誤。
更多信息,參見 Creating and Opening Files。
- 同步和異步 I/O 句柄
CreateFile 函數可以創建的文件或設備句柄可以是同步也可以是異步的。一個同步句柄會導致當執行 I/O 調用函數時,調用者會被阻塞知道函數執行結束;而一個異步文件句柄在調用 I/O 函數時,無論 I/O 操作是否執行完成,調用者都會立刻返回。
正如前面所闡述的,使用同步 I/O 還是異步 I/O 由在 dwFlagsAndAttributes 參數中是否指定了 FILE_FLAG_OVERLAPPED 標記位決定。此外異步 I/O 會有一些復雜性和潛在的陷阱,更多信息,參見 Synchronous and Asynchronous I/O。
- 文件流
在 NTFS 文件系統中,你可以使用 CreateFile 函數在一個文件中創建分離的流。想了解更多信息,參見 File Streams。
- 目錄
程序無法使用 CreateFile 函數創建一個目錄,因此對目錄操作時,在 dwCreationDisposition 參數里指定 OPEN_EXISTING 標記位才是合法的。為了創建一個目錄,程序必須調用 CreateDirectory 函數或 CreateDirectoryEx 函數。
若要用 CreateFile 函數打開一個目錄,需在 dwFlagsAndAttributes 參數里指定 FILE_FLAG_BACKUP_SEMANTICS 標記位。當程序沒有 SE_BACKUP_NAME 和 SE_RESTORE_NAME 權限時,會觸發適當的安全檢查。
在 FAT 或 FAT32 文件系統中,如果我們在執行磁盤碎片整理過程中,使用 CreateFile 函數打開一個目錄,那么不要指定 MAXIMUM_ALLOWED 訪問權限;如果這樣做,則對目錄的訪問將被拒絕;應使用 GENERIC_READ 訪問權限替代之。
更多信息,參見 About Directory Management。
- 物理磁盤和分區
對磁盤或分區的直接訪問是受限制的。更多信息,參見“在 Windows Vista 和 Windows Server 2008 中對文件系統和存儲堆棧進行的更改可限制對磁盤和卷的直接訪問”,網址為 http://support.microsoft.com/kb/942448。
Windows Server 2003 和 Windows XP: 對磁盤或分區的直接訪問是不受限制的。
你可以使用 CreateFile 函數打開一個物理磁盤或一個磁盤分卷,它會返回一個直接訪問存儲設備(DASD)句柄,這個句柄可以被 DeviceIoControl 函數所使用。這允許你直接訪問磁盤或分區,例如磁盤的元數據分區表。然而,這會使得磁盤或分區的數據存在數據丟失的可能,因為使用這種方法對磁盤一次不正確的寫操作可能使得操作系統無法識別修改后的數據。為了保證數據的完整性,要確保對 DeviceIoControl 函數足夠熟悉,且了解其他API在使用文件系統句柄和直接訪問句柄時,有什么區別。
若想對磁盤和分區直接訪問成功執行,以下條件必須被滿足:
調用者必須擁有 administrative 權限。更多信息,參見 Running with Special Privileges
dwCreationDisposition 參數必須指定 OPEN_EXISTING 標記位。
當打開一個分區或者軟盤時,dwShareMode 參數必須指定 FILE_SHARE_WRITE 標記位
注意:dwDesiredAccess 參數可以為 0,這允許程序不訪問設備、就可以詢問設備屬性。例如:程序可以獲得軟盤驅動器的大小和其支持的格式卻不用直接訪問軟盤。這還可以用於讀取一些不需要獲取高級別的數據讀、寫許可的就能讀取的數據。
當打開一個物理驅動器 x:,則 lpFileName 字符串格式如下:”\.\PhysicalDriverX”。硬盤下標從 0 開始。下表顯示了一個有關物理驅動器字符串格式的例子:
字符串 含義
“\.\PhysicalDrive0” 打開第一個磁盤驅動器
“\.\PhysicalDrive2” 打開第三個磁盤驅動器
為了得到一個物理磁盤驅動器的 ID 值,需要先獲得執行其的句柄,然后帶入 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 調用 DeviceIoControl 函數。
關於如何打開一個物理驅動器,參見 Calling DeviceIoControl 例子。
當打開一個分區或者可移動媒體驅動器(如一個磁盤驅動器或者閃盤驅動器),那么字符串 lpFileName 應該為以下格式 “\.\X:”。不要使用反斜線(\),這個符號表示驅動器的根目錄。下表是一些驅動器目錄字符串的例子:
字符串 含義
“\.\A:” 打開軟盤 A
“\.\C:” 打開磁盤驅動器 C
“\.\C:\” 打開 C 盤的文件系統
你也可以通過磁盤分區名字來打開一個磁盤分區。更多信息,參見 Naming a Volume。
一個分區可以有多個文件系統。一些特定的文件系統中,分區句柄被以禁止緩存方式打開,即使 CreateFile 函數並未指定禁止緩存選項。你可以假定所有微軟文件系統的分區句柄都是禁止緩存的,且對無緩存文件的某些限制同樣適用於分區句柄。
一個文件系統可能會也可能不會要求緩存對齊,即使數據是禁止緩存的。然而,如果在打開一個分區時指定了禁止緩存選項,無論加載在分區上的是何種文件系統,緩沖對齊都是強制要求的。當你打開一個分區時,推薦打開禁止緩存選項,且遵循禁止緩存 I/O 限制。
注意:讀寫分區的最后幾個扇區時,你必須調用 DeviceIoControl 函數並且指定 FSCTL_ALLOW_EXTENDED_DASD_IO 標記位。這會告知文件系統,調用分區的讀寫函數時,不要進行任何的 I/O 邊界檢查,而是由設備驅動器來執行邊界檢查。
- Changer Device
DeviceIoControl 函數設置控制代碼為 IOCTL_CHANGER_* 時,會接受一個指向 changer device 的句柄。要打開一個 changer device,使用如下格式的文件名:”\.\Changerx”,其中 x 表示要打開設備的下標,下標從 0 開始。如要在程序中使用 C 或者 C++ 打開 0 號 changer device,使用如下格式的文件名:”\\.\Changer0”。
- 磁帶驅動器
你可以通過使用如下形式的名稱來打開一個磁帶驅動器:”\.\TAPEx”,x 表示要打開的驅動器的下標,下標從 0 開始。 如要使用 C 或 C++ 打開 0 號磁帶驅動器,使用如下格式:”\\.\TAPE0”.
更多信息,參見 Backup。
- 通信資源
CreateFile 函數可以創建指向通信資源的句柄,如串行端口 COM1。 要打開一個通信資源,dwCreationDisposition 參數必須設置為 OPEN_EXISTING,dwShareMode 參數必須設置為 0(即只能由自己訪問),且 hTemplateFile 參數必須為 NULL。讀、寫或者讀/寫權限可以指定任意一個,且此句柄可用於異步 I/O。
如果要指定一個端口號大於 9 的 COM 端口,使用以下的語法:”\.\COM10”。此語法適用於所有端口號和所有允許 COM 端口號被指定的硬件。
更多關於通信的信息,參見 Communications。
- 控制台
你可以用 CreateFile 函數創建一個指向控制台輸入(COCNIN$)的句柄。如果進程通過繼承或復制獲得這個句柄,它還可以創建一個指向活動屏幕緩存的句柄。調用進程必須被附加到一個被繼承的控制台或者一個通過 AllocConsole 函數分配到的控制台。有關控制台句柄的參數設置如下:
參數 | 值 |
---|---|
lpFileName | 1.使用 CONIN值指向控制台輸入 2.使用 CONOUT值指向控制台輸出 3.CONIN 獲得一個指向控制台輸入緩存的句柄,即使控制台標准輸入句柄被 SetStdHandle 函數重定向了。使用 GetStdHandle 函數可以獲取標准輸入句柄 4.使用 CONOUT 獲取一個執行活動屏幕緩存的句柄,即使標准輸出句柄被 SetStdHandle 函數重定向了。使用 GetStdHandle 函數可以獲取標准輸出句柄 |
dwDesiredAccess | 更推薦使用 GENERIC_READ GENERIC_WRITE,但任選其一也可以用於設置權限 |
dwShareMode | 1.當打開 CONIN 時,要指定 FILE_SHARE_READ;當打開 CONOUT 時,要指定 FILE_SHARE_WRITE 2.如果這個控制台是調用進程通過繼承獲得的,或如果一個子進程要想訪問這個控制台,此參數必須設置為 FILE_SHARE_READ FILE_SHARE_WRITE |
lpSecurityAttributes | 如果你想此控制台被繼承,那么 SECURITY_ATTRIBUTES 結構體的 bInheritHandle 成員必須為 TRUE |
dwCreationDisposition | 當使用 CreateFile 函數打開一個控制台時,你必須指定 OPEN_EXISTING |
dwFlagsAndAttributes | 忽略 |
hTemplateFile | 忽略 |
下表是 dwDesiredAccess 和 lpFileName 參數取不同值時的結果:
lpFileName | dwDesiredAccess | 結果 |
---|---|---|
“CON” | GENERIC_READ | 打開一個控制台程序用於讀操作 |
“CON” | GENERIC_WRITE | 打開一個控制台程序用於寫操作 |
“CON” | GENERIC_READ GENERIC_WRITE | 此時 CreateFile 函數執行失敗;GetLastError 函數返回 ERROR_FILE_NOT_FOUND |
- 郵槽
如果 CreateFile 函數打開郵槽,那么當客戶端試圖打開一個本地郵槽,而服務端並沒有使用 CreateMailSlot 函數創建這個郵槽時,則返回 INVALID_HANDLE_VALUE。
更多信息,參見 Mailslots。
- 管道
如果 CreateFile 函數打開一個客戶端的命名管道,則此函數使用任意處於監聽狀態的命名管道句柄實例。進程可以無限復制命名管道句柄,但是當它被打開后,命名管道無法被另一個客戶端再次打開。被指定的命名管道訪問權限必須與使用函數 CreateNamedPipe 創建命名管道時,在 dwOpenMode 參數中設置的權限相兼容。
如果 CreateNamedPipe 函數沒有在服務端被成功調用,則命名管道不會被創建且 CreateFile 函數執行失敗,且返回 ERROR_FILE_NOT_FOUND。
如果在服務器上有至少一個活動的管道實例,但是不存在監聽者管道,即所有的管道實現在此時都被連接了,CreateFile 函數執行失敗且返回錯誤信息ERROR_PIPE_BUSY。
更多信息,參見 Pipes。
需求
Minimum supported client Windows XP [僅桌面應用程序]
Minimum supported server Windows 2003 服務器版 [僅桌面應用程序]
Header FileAPI.h (包含於 Windows.h)
在 Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003 和 Windows XP 系統上的 WinBase.h (包含於 Windows.h)
Library Kernel32.lib
DLL Kernel32.dll
Unicode and ANSI names CreateFileW (Unicode) 和 CreateFileA (ANSI)