原型
HANDLE WINAPI CreateFile(
_In_ LPCTSTR lpFileName,
_In_ DWORD dwDesiredAccess,
_In_ DWORD dwShareMode,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile
);
参数中的
_In_
和_In_opt_
_In_
:说明宏:本身没有意义,作用来表明参数,说明是输入
_In_opt_
:说明是输出,要特别注意,其中是否分配了空间
参数(参考维基百科)
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 中设置的
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 |
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 设置为 0 |
OPEN_EXISTING | 1.仅当文件或设备存在时,才打开它 2.如果指定的文件或设备不存在,函数执行失败且 last-error code 设置为 ERROR_FILE_NOT_FOUND(2) |
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 中定义的属性值
- 以下的属性和标记位可能只适用于文件的打开,而并非支持所有其他 CreateFile 函数可以打开的设备
属性 | 含义 |
---|---|
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 | 文件用于存储临时数据 |
FILE_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 Buffering |
FILE_FLAG_OPEN_NO_RECALL | 文件数据被请求,但它不应该继续在远程存储器中被定位。文件数据不应该传输回本地存储器。这个标记位被远程存储系统所使用 |
FILE_FLAG_OPEN_REPARSE_POINT | 1.不会发生正常的 reparse point 过程。 CreateFile 函数将会尝试去打开一个 reparse point。当一个文件被打开,无论控制 reparse point 的过滤器是否可操作,都会返回一个文件句柄 2.此标记无法与 CREATE_ALWAYS 标记位共同使用 3.如果文件不是一个 reparse point,那么此标记位无效 |
FILE_FLAG_OVERLAPPED | 1.此文件或设备被打开或创建,用于异步 I/O 2.当后续的 I/O 操作通过此句柄执行完成,则 OVERLAPPED 结构中指定的事件会被设置为受信状态 3.如果此标记位被指定,此文件可以被用于同步读写操作 4.如果此标记为未被指定,则 I/O 操作被序列化,即使对读写函数的调用指定了一个 OVERLAPPED 结构 |
FILE_FLAG_POSIX_SEMANTICS | 遵循 POSIX 规则,这包括允许多个文件名,只是在不同的情况下,为支持该命名规则的文件系统。当使用此选项时要小心,因为一个使用此标记位创建的文件可能无法被某些为 MS-DOS 或 16 位 Windows 操作系统所编写的程序所访问 |
FILE_FLAG_RANDOM_ACCESS | 1.文件访问为随机访问。此系统可以使用这个用于优化文件缓存 2.如果文件系统不支持 I/O 缓冲和 FILE_FLAG_NO_BUFFERING 标记,则此标记位无效 3.更多信息,参见 Caching Behavior |
FILE_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 Behavior |
FILE_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是一个宏
CreateFile是一个宏,调用的是CreateFileW或者CreateFileA
两者在参数的类型上会有点不同:在文件名参数那会有类型区别
为了方便ASCII和UNICODE进行自由切换
一开始,CreateFile函数是使用的窄字节,后来发现不够用了,所以就做出了CreateFileA,用于兼容窄字节,CreateFileW,用于推广宽字节,把CreateFile做成一个宏,可以在调用的时候根据实际情况进行版本调用,发现不够用了,所以就做出了CreateFileA,用于兼容窄字节,CreateFileW,用于推广宽字节,把CreateFile做成一个宏,可以在调用的时候根据实际情况进行版本调用
THCAR *filename=TEXT(“asdf”);
这套做法可以达到效果,但是在其它平台上不被承认
备注(来自维基百科)
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 函数决定