创建和打开文件

CreateFile 函数可以创建新文件或打开现有文件。 必须指定文件名、创建说明和其他属性。 当应用程序创建新文件时,操作系统会将其添加到指定的目录。

操作系统将唯一标识符(称为 句柄)分配给使用 CreateFile 打开或创建的每个文件。 应用程序可以将此句柄用于读取、写入和描述文件的函数。 在关闭对该句柄的所有引用之前,它才有效。 当应用程序启动时,如果句柄被创建为可继承,它将从启动它的进程继承所有打开的句柄。

在尝试使用该句柄访问文件之前,应用程序应检查 CreateFile 返回的句柄的值。 如果发生错误,将 INVALID_HANDLE_VALUE 句柄值,并且应用程序可以使用 GetLastError 函数获取扩展错误信息。

当应用程序使用 CreateFile 时,它必须使用 dwDesiredAccess 参数来指定它是打算从文件读取、写入文件,还是同时读取和写入,还是两者都不打算读取和写入。 这称为请求 访问模式。 应用程序还必须使用 dwCreationDisposition 参数来指定在文件已存在时要执行的操作,称为 创建处置。 例如,应用程序可以调用将 dwCreationDisposition 设置为 CREATE_ALWAYSCreateFile 以始终创建新文件,即使已存在同名文件 (从而覆盖现有文件) 。 此操作是否成功取决于上一个文件的属性和安全设置等因素, (请参阅以下部分以获取) 的详细信息。

应用程序还使用 CreateFile 来指定是要共享文件进行读取、写入,还是两者都不共享。 这称为 共享模式。 未共享的打开文件 (dwShareMode 设置为零,) 不能再次由打开它的应用程序或其他应用程序打开,直到其句柄已关闭。 这也称为独占访问。

当进程使用 CreateFile 尝试打开已在共享模式下打开的文件 (dwShareMode 设置为有效的非零值) 时,系统会将请求的访问和共享模式与打开文件时指定的模式进行比较。 如果指定的访问或共享模式与上一次调用中指定的模式冲突, 则 CreateFile 会失败。

下表说明了使用各种访问模式和共享模式对 CreateFile 的两个调用的有效组合, (dwDesiredAccessdwShareMode 分别) 。 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_READ、FILE_SHARE_WRITE
  • GENERIC_WRITEFILE_SHARE_READ
  • GENERIC_WRITEFILE_SHARE_READ、FILE_SHARE_WRITE
  • GENERIC_READGENERIC_WRITEFILE_SHARE_READ
  • GENERIC_READGENERIC_WRITEFILE_SHARE_READ、FILE_SHARE_WRITE
GENERIC_WRITEFILE_SHARE_READ
  • GENERIC_READFILE_SHARE_WRITE
  • GENERIC_READFILE_SHARE_READ、FILE_SHARE_WRITE
GENERIC_WRITEFILE_SHARE_WRITE
  • GENERIC_WRITEFILE_SHARE_WRITE
  • GENERIC_WRITEFILE_SHARE_READ、FILE_SHARE_WRITE
GENERIC_WRITEFILE_SHARE_READ FILE_SHARE_WRITE
  • GENERIC_READFILE_SHARE_WRITE
  • GENERIC_READFILE_SHARE_READ、FILE_SHARE_WRITE
  • GENERIC_WRITEFILE_SHARE_WRITE
  • GENERIC_WRITEFILE_SHARE_READ、FILE_SHARE_WRITE
  • GENERIC_READGENERIC_WRITE、FILE_SHARE_WRITE
  • GENERIC_READGENERIC_WRITEFILE_SHARE_READFILE_SHARE_WRITE
GENERIC_READGENERIC_WRITE、FILE_SHARE_READ
  • GENERIC_READFILE_SHARE_READ、FILE_SHARE_WRITE
GENERIC_READGENERIC_WRITE、FILE_SHARE_WRITE
  • GENERIC_WRITEFILE_SHARE_READ、FILE_SHARE_WRITE
GENERIC_READGENERIC_WRITEFILE_SHARE_READFILE_SHARE_WRITE
  • GENERIC_READFILE_SHARE_READ、FILE_SHARE_WRITE
  • GENERIC_WRITEFILE_SHARE_READ、FILE_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,即使对于此特定用例,如果打算创建一个“new” (空) 文件来代替现有的) ,则它实际上并不是这样的错误 (。

打开现有文件 (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_POINTFILE_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