Windows核心编程-CreateFile详解

文件内核对象

各种设备及其常见用途:

设备 常见用途
文件 永久存储任何数据
目录 属性和文件压缩的设置
逻辑磁盘驱动器 格式化驱动器
物理磁盘驱动器 访问分区表
串口 通过电话线传输数据
并口 将数据传输至打印机
邮件槽 一对多数据传输,通常是通过网络传到另一台运行Windows机器上
命名管道 一对一数据传输,通常是通过网络传到另一台运行Windows机器上
匿名管道 单机上的一对一数据传输(绝对不会跨网络)
套接字 报文或数据流的传输,通常是通过网络传到任何支持套接字的机器上
控制台 文本窗口的屏幕缓存

用来打开各种设备的函数:

设备 用来打开设备的函数
文件 CreateFile(pszName 为路径名或UNC路径名)
目录 CreateFile(pszName为路径名或UNC路径名)。如果调用 CreateFile 的时候指定 FILE_FLAG_BACKUP_SEMANTICS标志,那么Windows允许我们打开一个目录。打开目录使我们能够改变目录的属性
逻辑磁盘驱动器 CreateFile(pszName 为“\.\x:”)。如果指定的字符串是”\.\x:”的形式,那么Windows允许我们打开一个逻辑磁盘驱动器,其中的x是驱动器的盘符。打开驱动器使我们能够格式化驱动器或检测驱动器媒介的大小
物理磁盘驱动器 CreateFile(pszName 为 “\\.\PHYSICALDRIVEx”)。如果指定的字符串是“\\.\PHYSICALDRIVEx”的形式,那么Windows允许我们打开一个物理磁盘驱动器,其中的x是物理驱动器号。例如,读写第一个物理磁盘驱动器的扇区——\\.\PHYSICALDRIVE0。打开物理驱动器使我们能直接访问磁盘分区表。打开物理驱动器有潜在的危险,错误地写入设备可能会导致操作系统的文件系统无法访问磁盘的内容
串口 CreateFile(pszName 为”COMx”)
并口 CreateFile(pszName, 为”LPTx”)
邮件槽服务器 CreateMailslot(pszName, 为 “\\.\mailslot\mailslotname”)
邮件槽客户端 CreateFile(pszName 为”\\servername\mailslotname”)
命名管道服务器 CreateNamedPipe(pszName 为”\\.\pipe\pipename”)
命名管道客户端 CreateFile(pszName 为”\\servername\pipe\pipename”)
匿名管道 CreatePipe用来打开服务器和客户端
套接字 Socket, accept 或 AcceptEx
控制台 CreateConsoleScreenBufferGetStdHandle

以上CreateFile函数都是返回对应设备的句柄,通过设备句柄我们可与对应的设备进行通信,也可以使用对应设备的特有API进行设置。

调用SetCommConfig设置串口的波特率:

BOOL SetCommConfig(
    HANDLE  hCommDev,
    LPCOMMCONFIG    pCC,
    DWORD   dwSize);

邮件槽在等待读取数据时,可以调用SetMailslotInfo来设置一个超时值:

BOOL SetMailslotInfo(
    HANDLE hMailslot,
    DWORD dwReadTimeout);

获取文件类型GetFileType的返回值:

描述
FILE_TYPE_UNKNOWN 指定的文件为未知类型
FILE_TYPE_DISK 指定的文件是一个磁盘文件
FILE_TYPE_CHAR 指定的文件是一个字符文件,一般来说是一个并口设备或控制台
FILE_TYPE_PIPE 指定的文件是一个命名管道或匿名管道

1.文件内核对象打开及操作

HANDLE CreateFile(
    PCTSTR  pszName,            //文件设备名
    DWORD   dwDesiredAccess,    //读取方式
    DWORD   dwShareMode,        //共享模式
    PSECURITY_ATTRIBUTES    psa,    //安全属性
    DWORD   dwCreationgDisposition, //
    DWORD   dwFlagsAndAttributes,
    HANDLE  hFileTemplate);
dwDesiredAccess
含义
0 不希望从设备读取数据或向设备写入数据。如果只想改变设备的配置(如:修改文件的时间戳),可以传0
GENERIC_READ 允许对设备进行只读访问
GENERIC_WRITE 允许对设备进行只写访问,该选项并没有隐含 GENERIC_READ标志
dwShareMode
含义
0 要求独占对设备的访问。如果设备已经打开,CreateFile 调用会失败;如果成功地打开了设备,后续的 CreateFile 调用会失败
FILE_SHARE_READ 如果有其他对象要用该设备,我们要求它们不得修改设备的数据;如果设备已经以写入方式或独占方式打开,那么CreateFile调用会失败
FILE_SHARE_WRITE 如果有其他内核对象要使用该设备,则要求它们不得读取设备的数据
FILE_SHARE_DELETE 当对文件进行操作的时候,我们不关心文件是否被逻辑删除或移动。在Windows内部,系统会先将文件标记为待删除,然后当该文件所有已打开的句柄都被关闭的时候,再将其真正的删除
dwCreationgDisposition
含义
CREATE_NEW 告诉CreateFile创建一个新文件,如果同名文件已经存在,那么 CreateFile调用会失败
CREATE_ALWAYS 告诉CreateFile无论同名是否存在都创建新文件,若文件存在,则覆盖
OPEN_EXISTING 告诉CreateFile打开一个已有的文件或设备,如果文件或设备不存在,那么CreateFile调用会失败
OPEN_ALWAYS 告诉CreateFile打开一个已有的文件,如果文件存在,那么CreateFile会直接打开文件,如果不存在,则会创建一个新文件
TRUNCATE_EXISTING 告诉CreateFile打开一个已有的文件并将文件大小截断为0字节,如果文件不存在,那么CreateFile调用会失败
dwFlagsAndAttributes
  • 该参数的用途:
    • 允许我们设置一些标志来微调与设备之间的通信;
    • 如果设备是一个文件,我们还能够设置文件的属性.
含义
通信标志–缓存
FILE_FLAG_NO_BUFFERING 该标志表示在访问文件的时候不要使用任何数据缓存
FILE_FLAG_SEQUENTIAL_SCAN 指定系统顺序地访问文件,系统从文件读取的数据量会超过我们的要求(减少硬盘访问),指定了FILE_FLAG_NO_BUFFERING标志,该标志不生效
FILE_FLAG_RANDOM_ACCESS 该标志表示系统不要提前读取文件数据(指定FILE_FLAG_NO_BUFFERING,则该标志不生效)
FILE_FLAG_WRITE_THROUGH 禁止写入文件时,将数据缓存在内存中(减少数据丢失的可能性)
通信标志–其他标志
FILE_FLAG_DELETE_ON_CLOSE 文件所有的句柄都被关闭后,删除该文件
FILE_FLAG_BACKUP_SEMANTICS 用于备份和恢复软件。在打开或创建任何文件之前,为了确保视图打开文件或创建文件的进程具有所需的访问特权
FILE_FLAG_POSIX_SEMANTICS 让CreateFile在创建文件或打开文件时,以区分大小写的方式来查找文件名
FILE_FLAG_OPEN_REPARSE_POINT 告诉系统忽略文件的重解析属性(重解析属性允许一个文件系统过滤器对打开文件、读取文件、写入文件以及关闭文件这些行为进行修改)
FILE_FLAG_OPEN_NO_RECALL 该标志告诉系统不要将文件内容刚从脱机存储器(offline storage,比如磁带)恢复到联机存储器(即online storage, 如硬盘)
FILE_FLAG_OVERLAPPED 该标志告诉系统我们想以异步方式来访问设备
文件设置
FILE_ATTRIBUTE_ARCHIVE 应用程序用该标志来将文件标记为待备份或待删除。当CreateFile创建一个新文件时,会自动设置该标志
FILE_ATTRIBUTE_ENCRYPTED 文件是经过加密的
FILE_ATTRIBUTE_HIDDEN 文件是隐藏的。它不会出现在通常的目录清单中
FILE_ATTRIBUTE_NORMAL 文件没有其他属性。只有单独使用的时候,这个标志才有效
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 内容索引服务(content indexing service)不会对文件进行索引
FILE_ATTRIBUTE_OFFLINE 文件虽然存在,但文件内容已经被转移到脱机存储中
FILE_ATTRIBUTE_READONLY 文件只读
FILE_ATTRIBUTE_SYSTEM 文件是操作系统的一部分,专供操作系统使用
FILE_ATTRIBUTE_TEMPORARY 文件数据只会使用一小段时间。为了将访问时间降至最低,会尽量将文件数据保存在内存中

2.使用文件设备

  1. 获得文件的大小

    BOOL GetFileSizeEx(
        HANDLE  hFile,                  // 文件句柄
        PLARGE_INTEGER  pliFileSize);   //64位标识文件大小
    
    typedef union _LARGE_INTEGER {
        struct {
            DWORD   LowPart;        //Low 32-bit unsigned value
            LONG    HighPart;       //High 32-bit signed value
        };
        LONGLONG    QuadPart;       //Full 64-bit signed value
    } LARGE_INTEGER, *PLARGE_INTEGER;
  2. 设置文件指针

    每调用一次CreateFile函数都会打开一个文件内核对象用于管理文件,每个内核对象内部都维护了一个文件指针,表示应该在哪里执行下一次同步读取或写入操作。

    BOOL SetFilePointerEx(
        HANDLE  hFile,
        LARGE_INTEGER   liDistanceToMove,    //指针移动的距离(多少字节)
        PLARGE_INTEGER  pliNewFilePointer,  //移动后返回的新指针
        DWORD   dwMoveMethod);            //如何解释liDistanceToMove,即从哪个位置开始移动liDistanceToMove的距离(FILE_BEGIN, FILE_CURRENT, FILE_END)
    • 注意事项:
      • 将文件指针的值设为超过文件当前的大小是正当操作,除非在该位置向文件写入数据或调用 SetEndOfFile 才会改变文件大小;
      • 如果SetFilePointerEx操作的文件是用FILE_FLAG_NO_BUFFERING标志打开的,那么文件指针只能被设置为扇区大小的整数倍;
  3. 设置文件尾

    BOOL SetEndOfFile(HANDLE hFile);

    SetEndOfFile函数会根据文件对象的文件指针当前所在的位置来截断文件的大小或增大文件的大小

    HANDLE hFile = CreateFile(...);
    LARGE_INTEGER liDistanceToMove;
    liDistanceToMove.QuadPart = 1024;
    SetFilePointerEx(hFile, liDistanceToMove, NULL, FILE_BEGIN);
    SetEndOfFile(hFile);
    CloseHandle(hFile);

你可能感兴趣的:(windows核心编程)