zoukankan      html  css  js  c++  java
  • 第6章 Overlapped I/O, 在你身后变戏法 ---Win32 文件操作函数 -2

        Win32 之中有三个基本的函数用来执行 I/O,它们是:
            i CreateFile()
            i ReadFile()
            i WriteFile()
        没有另外哪一个函数用来关闭文件,只要调用 CloseHandle() 即可。本章对于这些函数将只涵盖其与 overlapped I/O 有关的部分,至于其他和文件 I/O有关的部分,请参考 Win32 Programmer's Reference。
            CreateFile() 可以用来打开各式各样的资源,包括(但不限制于):
                i 文件(硬盘、软盘、光盘或其他)
                i 串行口和并行口(serial and parallel ports)
                i Named pipes
                i Console(请看第8章)
            CreateFile() 的函数原型看起来像这样:
            
            HANDLE CreateFile(
                LPCTSTR lpFileName, // 指向文件名称
                DWORD dwDesiredAccess, // 存取模式(读或写)
                DWORD dwShareMode, // 共享模式(share mode)
                LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 指向安全属性结构
                DWORD dwCreationDisposition, // 如何产生
                DWORD dwFlagsAndAttributes, // 文件属性
                HANDLE hTemplateFile // 一个临时文件,将拥有全部的属性拷贝
            );
                其中第6个参数 dwFlagsAndAttributes 是使用 overlapped I/O 的关键。这个参数可以藉由许多个数值组合在一起而完成,其中对于本处讨论最重要的一个数值便是 FILE_FLAG_OVERLAPPED。你可以藉着这个参数,指定使用同 步(传统的)调用,或是使用 overlapped(异步)调用,但不能够两个都指定。换句话说,如果这个标记值设立,那么对该文件的每一个操作都将是overlapped。
        一个不常被讨论的 overlapped I/O 性质是,它可以在同一时间读(或写)文件的许多部分。微妙处在于这些操作都使用相同的文件 handle。因此,当你使用 overlapped I/O 时,没有所谓“目前的文件位置”这样的观念。每一次读或写的操作都必须包含其文件位置。
        如果你发出许多个 overlapped 请求,那么执行次序无法保证。虽然你在单一磁盘中对文件进行操作时很少会有这样的行为,但如果面对多个磁盘,或不同种类的设备(如网络和磁盘),就常常会看到 I/O 请求完全失去次序。
        你将不可能藉由调用 C runtime library 中的 stdio.h 函数而使用overlapped I/O。因此,没有很方便的方法可以实现 overlapped text-based I/O。例如,fgets() 允许你一次读取一行文字,但你不能够使用 fgets()、fprintf() 或任何其他类似的 C runtime 函数来进行 overlapped I/O。
        Overlapped I/O 的基本型式是以 ReadFile() 和 WriteFile() 完成的。这个函数的原型如下:
            
            BOOL ReadFile(
                HANDLE hFile, // 欲读之文件
                LPVOID lpBuffer, // 接收数据之缓冲区
                DWORD nNumberOfBytesToRead, // 欲读取的字节个数
                LPDWORD lpNumberOfBytesRead, // 实际读取的字节个数的地址
                LPOVERLAPPED lpOverlapped // 指针,指向 overlapped info
            );


            BOOL WriteFile(
                HANDLE hFile, // 欲写之文件
                LPCVOID lpBuffer, // 储存数据之缓冲区
                DWORD nNumberOfBytesToWrite, // 欲写入的字节个数
                LPDWORD lpNumberOfBytesWritten, // 实际写入的字节个数的地址
                LPOVERLAPPED lpOverlapped // 指针,指向 overlapped info
            );
        这两个函数很像 C runtime 函数中的 fread() 和 fwrite(),差别在于最后一个参数lpOverlapped 。如果CreateFile() 的第6 个参数被指定为FILE_FLAG_ OVERLAPPED,你就必须在上述的 lpOverlapped 参数中提供一个指针,指向一个 OVERLAPPED 结构。

    OVERLAPPED 结构
        OVERLAPPED 结构执行两个重要的功能。第一,它像一把钥匙,用以识别每一个目前正在进行的 overlapped 操作。第二,它在你和系统之间提供了一个共享区域,参数可以在该区域中双向传递。
        OVERLAPPED 结构看起来像这样:
        
            typedef struct _OVERLAPPED {
                DWORD Internal;
                DWORD InternalHigh;
                DWORD Offset;
                DWORD OffsetHigh;
                HANDLE hEvent;
            } OVERLAPPED, *LPOVERLAPPED;
    OVERLAPPED 结构中的成员
        表格6-1 描述 OVERLAPPED 结构中的每一个成员。
                表格6-1 OVERLAPPED 结构中的成员(栏位)
        成员名称         说 明
        Internal        通常它被保留。然而当 GetOverlappedResult() 传回 FALSE 并且GetLastError() 并非传回 ERROR_IO_PENDING 时,这个栏位将内含一个视系统而定的状态
        InternalHigh         通常它被保留。然而当 GetOverlappedResult() 传回 TRUE 时,这个栏位将内含“被传输数据的长度”
        Offset             文件之中开始被读或被写的偏移位置(以字节为单位)。该偏移位置从文件头开始起算。如果目标设备(例如 pipes)并没有支持文件位置,此栏位将被忽略
        OffsetHigh         64 位的文件偏移位置中,较高的 32 位。如果目标设备(例如 pipes)并没有支持文件位置,此栏位将被忽略
        hEvent             一个手动重置(manual-reset)的 event 对象,当 overlapped I/O 完成时即被激发。ReadFileEx() 和 WriteFileEx() 会忽略这个栏位,彼时它可能被用来传递一个用户自定义的指针

        由于 OVERLAPPED 结构的生命期超越 ReadFile() 和 WriteFile() 函数,所以把这个结构放在一个安全的地方是很重要的事情。通常局部变量并不是一个安全的地方,因为它会很快就越过了生存范围(out of scope)。最安全的地方就是 heap。

        现在我们有了所有的基础物质,让我们看看如何运用它们。

  • 相关阅读:
    由一次自建库迁移到阿里云RDS引发的性能问题。
    pycharm2017自建注册服务器
    linux 邮件工具利器sendEmail时效超好
    python利用smtplib和MIMETYPE发送邮件
    如何去除本地文件与svn服务器的关联
    【转】nginx提示:500 Internal Server Error错误的解决方法
    Eclipse SVN插件安装
    Weblogic用户名密码获取
    Io 异常: The Network Adapter could not establish the connection
    Oracle修改字段名、字段数据类型
  • 原文地址:https://www.cnblogs.com/azbane/p/7606398.html
Copyright © 2011-2022 走看看