CreateFile()逻辑梳理(二)
二、涉及技术领域
dwFlagsAndAttributes用于指定文件或设备的属性以及一系列与特定技术领域相关的参数值。如果不希望指定某个特定属性,那么FILE_ATTRIBUTE_NORMAL是一个常用的默认值,如果指定了其他任何一个特定的属性,FILE_ATTRIBUTE_NORMAL就不起作用了。
下面先介绍几个用于dwFlagsAndAttributes的几个属性值,基本是用于文件的。
| FILE_ATTRIBUTE_READONLY | 文件具有只读属性。 |
| FILE_ATTRIBUTE_HIDDEN | 文件被设置隐藏属性。 |
| FILE_ATTRIBUTE_SYSTEM | 文件是操作系统的一部分或只能由系统使用。 |
| FILE_ATTRIBUTE_ARCHIVE | 文件被设置存档属性。 |
| FILE_ATTRIBUTE_ENCRYPTED | 文件或文件夹被加密。对于文件,说明文件中的数据被加密存放;对于文件夹,说明该文件夹新创建文件的默认都要加密存放。 |
| FILE_ATTRIBUTE_OFFLINE | 说明文件数据实际存储在脱机存储中,该属性由Remote Storage系统管理,应用程序不要更改 |
| FILE_ATTRIBUTE_TEMPORARY | 文件用于临时存储。该属性使系统在缓存够用的情况下尽可能地不将临时文件数据写入磁盘,因为用完就会被删除。 |
只有在创建文件时指定这些属性才有意义,当打开现有文件时CreateFile()会忽略dwFlagsAndAttributes中的各种属性值,只采用其中的标志值(FILE_FLAGS_*)。
dwFlagsAndAttributes参数可以用的标志值有很多,分别适用于不同的设备或不同的场合。
如果希望在所有句柄都关闭后自动删除文件,可在调用CreateFile()时在dwFlagsAndAttributes加入FILE_FLAG_DELETE_ON_CLOSE标志。如果该文件已经被其他进程打开,只要它的共享模式中包含FILE_SHARE_DELETE就可以实现这种效果。
以下是其他用于各技术领域的标志位:
| 技术领域 | 标志位 | 说明 |
| 异步I/O | FILE_FLAG_OVERLAPPED | 指定要打开的文件或设备以异步方式进行I/O操作。后续的ReadFile()、WriteFile()操作都要传入OVERLAPPED结构,当I/O完成时,该结构中的事件对象会变成信号状态。 如果与FILE_FLAG_NO_BUFFERING结合使用会最大化异步操作的性能,因为不用再依赖于内存管理机制,内存管理是按同步机制操作的。但因为没有了缓存,还是有可能使某些操作变慢,而且有可能某些文件元数据会被缓存(比如新建一个空文件时),而要将这些元数据写入磁盘要调用FlushFileBuffer()。 |
| 缓存 | FILE_FLAG_NO_BUFFERING | 要求文件或设备的I/O操作以系统不提供缓存的方式进行处理,该标志并不影响磁盘本身缓存的使用。需要小心使用该标志,建议仔细研读文件缓存机制的文档。 |
| FILE_FLAG_RANDOM_ACCESS | 要求系统对随机访问进行缓存优化。如果系统不支持I/O缓存以及FILE_FLAG_NO_BUFFERING,该标志不起作用。 | |
| FILE_FLAG_SEQUENTIAL_SCAN | 要求系统按从头到尾顺序读取文件进行缓存优化,如果反向读取文件不要设置该标志。如果系统不支持I/O缓存以及FILE_FLAG_NO_BUFFERING,该标志不起作用。当应用程序以从头到尾的方式顺序读取文件时,设置该标志会显著提高性能。 本标志不能与FILE_FLAG_RANDOM_SCAN同时指定。 | |
| FILE_FLAG_WRITE_THROUGH | 要求系统直接将数据写入磁盘而不经过系统缓存,而且各种元数据(时间戳的更i新、重命名操作等)也会被写入磁盘。 将FILE_FLAG_WRITE_THROUGH与FILE_FLAG_NO_BUFFERING结合可取代在写操作后调用FlushFileBuffer()的做法,因为此时系统缓存不起作用,数据被直接写入磁盘,从而提高性能。 如果只指定FILE_FLAG_WRITE_THROUGH而不指定FILE_FLAG_NO_BUFFERING,此时系统缓存可用,数据会在写入系统缓存后不做停留直接写入磁盘。 | |
| 远程访问 | FILE_FLAG_OPEN_NO_RECALL | 访问远程文件时不将文件做本地缓存。 |
| 备份/恢复 | FILE_FLAG_BACKUP_SEMANTICS | 要求文件以备份或恢复地语义打开或创建,如果调用者有SE_BACKUP_NAME或SE_RESTORE_NAME特权,系统不会对调用者进行安全检查。 如果用CreateFile()打开一个目录则必须指定该标志。 |
| 符号链接 | FILE_FLAG_OPEN_REPARSE_POINT | ReparsePoint(重解析点)是Windows系统中一个高级文件系统特性,允许代码在文件系统中嵌入用户定义地元数据,当访问某个文件或目录时,如果它是一个重解析点,则系统会重新处理对该对象的请求,从而实现指向其他位置、改变对象行为或者进行特定操作的能力。 符号链接是一种特殊类型的重解析点,允许用户在文件系统中创建指向其他文件或目录的”快捷方式“。 如果打开了一个符号链接文件,在指定了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,受影响的是符号链接指向的目标。 |
| 会话相关 | FILE_FLAG_SESSION_AWARE | 文件或设备以会话感知的方式打开。如果该标志不指定,特定会话相关的设备无法被0号会话的进程打开。该标志只在Windows Server 2008 中被支持。 |
| POSIX | FILE_FLAG_POSIX_SEMANTICS | 以兼容POSIX标准的方式进行操作。这包括允许多个文件使用相同的名称,仅仅是字母大小写有区别等规范,使用该标志要格外小心,用该标志创建的文件可能无法被早期版本的Windows访问。 |
三、安全性
入口参数lpSecurityAttributes是一个SECURITY_ATTRIBUTES结构指针,该结构包含两个成员:一个可选的安全描述符,一个布尔值bInheritHandle,用于指明返回的句柄是否可被子进程继承。
当打开一个现有的文件或设备时,CreateFile()会忽略在lpSecurityAttributes中的安全描述符,但bInheritHandle仍然会起作用。
如果该参数为空值,那么CreateFile()返回的句柄不能被调用者的子进程继承,同时创建的文件会被赋予一个默认的安全描述符。
四、hTemplateFile
一个对模板文件具有GENERIC_READ权限的句柄,在创建新文件时,可从该模板文件获取希望赋给新文件的文件属性和扩展属性,如果时打开现有文件,该参数会被忽略。
以上对CreateFile()这个庞杂的函数进行了逻辑上的梳理,力图使大家在使用时不那么眼花缭乱。笔者在这里建议大家在使用前仔细阅读所涉及领域的文档,对背景信息了解足够充分后再进行程序设计。
