实验九 使用异步方式实现文件读\写

一、实验目的

  1. 了解Windows系统异步文件读/写的概念。
  2. 熟悉Windows系统文件读/写相关的API。
  3. 掌握采用异步方式实现文件读/写的相关参数设置。

二、实验准备

文件异步传输及相关API函数介绍

  1. 文件异步传输基本原理

文件异步传输是一种改变指令执行顺序的机制。一般而言,指令是顺序执行的,下一条指令必须在上一条指令执行完毕才可执行。因此当CPU遇到一条访问磁盘的指令时。应用程序需要等待磁盘访问结束后才能进行后续的工作。但如果后续工作与访问磁盘操作无关,这样的等待就显得很没有必要。Windows XP 系统中提供了异步传输机制可以解决这个问题。它通过打开文件时设置标志位表明文件采用异步传输方式,这样,进程不等待读写操作而继续执行。当指令必须用到磁盘访问结果的数据时,可通过一条Wait指令进行等待。
文件异步传输时,访问磁盘指令和等待指令之间的指令与磁盘访问并发进行。从而大大加快了系统处理I/O的速度。

  1. 相关API函数介绍

函数GetOverlappedResult()返回指定文件 命名通道或通信设备上OVERLAPPED操纵的结果。

  • 函数原型
Bool GetOverlappedResult(
HANDLE hFile                               //文件 命名通道或通信设备的句柄,
LPOVERLAPPED lpOverlapped,                //指向OVERLAPPED结构的指针
LPDWORD  lpNumberOfBytesTransferred,,       //指向实际传输字节数的指针
BOOL bWait                                 //等待标志
);

参数说明:

  1. hFile:文件 命名通道或通信设备的句柄,。
  2. lpOverlaooed:指向OVERLAPPED结构的指针。
  3. lpNumberOfBytesTransferred,:32位变量指针, 指向实际传输字节数。
  4. bWait : /等待标志。指定函数是否应等待被挂起的 要完成的OVERLAPPED操作。若为TURE,则OVERLAPPED操作完成之前该函数不返回;若为FASLE,则OVERLAPPED 被挂起,则函数返回FASLE,调用GetlastError()函数应返回ERROR_IO_INCOMPLETE。

返回值:

如果函数调用成功,则返回值为非0值。如果函数调用失败,则返回值为0.若要得到更多的错误信息,则调用函数GetLastError()。

其他相关的API函数的介绍

文件创建

函数CreateFile( ) 用于创建一个新文件,如果文件已经存在,则得到该文件的句柄。该函数的参数dwFalgsAndAttributes决定了文件的传输方式,对于普通的文件传输,可将参数设置为FILE_ATTRIBUTE_NORMAL;而若设置为FILE_FLAG_NO_BUFFERING,表示不使用高速缓存进行文件传输;若同时使用标志FILE_FLAG_NO_BUFFERING和FILE_FLAG_OVERLAPPED,可对文件进行异步传输;若设置为FILE_FLAG_SEQUENTIAL_SCAN,表示使用高速缓存进行文件的传输。

  • 函数原型
HANDLE CreateFile(LPCTSTR lpFileName,                                 //指向文件名的指针DWORD dwDesiredAccess,                            //读/写访问模式DWORD dwShareMode,                             //共享模式LPSECURITY_ATTRIBUTES lpSecurityAttributes,       //指向安全属性的指针DWORD dwCreationDisposition,                     //文件存在标志DWORD dwFlagsAndAttributes,                      //文件属性DWORD hTemplateFile                              //指向访问模板文件的句柄) ;
  • 参数说明
  1. lpFILEName:指向文件名的指针。
  2. dwDesiredAccess:指出访问文件的类型,可以是读访问、写访问、读 / 写访问或查询访问。该参数可以是表4-1中的组合。
  3. dwShareMode:指出文件共享模式。若dwShareMode的值为0,表示目标不能被共享。若要共享文件,可以使用表4-2中的组合。
  • 表4-1 不同值的描述

  • 描述
    0 查询访问
    GENERIC_READ 读访问,从文件中读出数据,且移动文件指针。当需要对文件进行读写时,该属性可以与GENERIC_WRITE组合使用
    GENERIC_WRITE 写访问,将数据写入文件,且移动文件指针。当需要对文件进行读/写时,该属性可以与GENERIC_READ组合使用
  • 表4-2 dwShareMode的值

  • 描述
    FILE_SHARE_DELETE 仅当删除访问时,对文件的打开操作才能成功
    FILE_SHARE_READ 仅当读访问时,对文件的打开操作才能成功
    FILE_SHARE_WRITE 仅当写访问时,对文件的打开操作才能成功
  1. lpSecurityAttributes:指向安全属性的指针。为NULL时,子进程可以继承该安全描述符。
  2. dwCreationDisposition:文件存在标志。指出当文件不存在时,可以对文件进行何种操作。可以取表4-3中的值。
  • 表4-3 dwCreationDisposition 的值
  • 描述
    CREAT_NEW 创建新文件。若文件已存在,则该函数调用失败
    CREAT_ALWAYS 创建新文件。若文件已存在,则该函数覆盖原文件的内容且清空现有属性
    OPEN_EXISTING 打开已存在文件,若文件不存在,则该函数打开失败
    OPEN_ALWAYS 若文件存在,则打开该文件,若文件不存在,则以CREAT_NEW方式创建文件
    TRUNCATE_EXISTING 打开文件,并将文件的大小截取为0
  1. dwFlagsAndAttributes:指出文件属性和标志。除了FILE_ATTRIBUTE_NORMAL属性之外,参数dwFlagsAndAttributes可以取表4-4中任何属性的组合。参数dwFlagsAndAttributes还可以取表4-5中任何属性的组合。
  • 表4-4 属性描述

  • 属性 描述
    FILE_ATTRIBUTE_ARCHIVE 文件可以被存档
    FILE_ATTRIBUTE_HIDDEN 文件可以被隐藏
    FILE_ATTRIBUTE_NORMAL 文件没有其他属性,该属性仅当单独时使用才有效
    FILE_ATTRIBUTE_OFFLINE 文件中的数据被脱机存储,文件中的数据不能立即有效
    FILE_ATTRIBUTE_READONLY 文件只能读
    FILE_ATTRIBUTE_SYSTEM 文件被系统使用
    FILE_ATTRIBUTE_TEMPORARY 文件被临时存储
  • 表4-5 属性补充

  • 属性 描述
    FILE_FLAG_WRITE_THROUGH 系统对文件的任何写操作,当缓冲的内容改变时立即写回磁盘
    FILE_FLAG_OVERLAPPED 异步读/写,使用该属性时,文件指针将不被保留
    FILE_FLAG_NO_BUFFERING 文件不使用缓冲
    FILE_FLAG_RANDOM_ACCESS 文件随机访问
    FILE_FLAG_SEQUENTIAL_SCAN 文件被顺序访问
    FILE_FLAG_DELETE_ON_CLOSE 当文件句柄关闭时,文件立即被删除
    FILE_FLAG_BACKUP_SEMANTICS 文件用于备份或转储
    FILE_FLAG_POSIX_SEMANTICS 文件访问遵循POSIX协议。
  1. hTemplateFile:指向访问模板文件的句柄,可以将其设置为空。
    返回值:文件创建成功,该函数返回文件句柄,否则返回INVALID_HANDLE_VALUE,可调用函数GetLastError( )查询失败的原因。
  • 用法举例
  • HANDLE handle;
    handle = CreateFile(“nobuffer.txt”,GENERIC_WRITE,NULL,NULL,CREATE_ALWAYS,
    NULL,NULL);
    //使用函数创建一个新文件nobuffer.txt,对该文件只能进行写操作
    

读文件

  • 函数Readfile( ) 从文件指针指示的位置开始读取文件中的数据。如果文件不是用FILE_FLAG_OVERLAPPED属性创建的,则文件指针移动到实际读出字节数所处的位置;如果文件是用FILE_FLAG_OVERLAPPED属性创建的,则文件指针由应用程序来调整其位置。
    函数原型:
 BOOL ReadFILE(HANDLE hFile,                              //要读的文件的句柄LPVOID lpBuffer,                           //指向文件缓冲区的指针DWORD nNumberOfBytesToRead,                //从文件中要读取的字节数LPDWORD lpNumberOfBytesRead,               //指向从文件中要读取的字节数的指针LPOVERLAPPED lpOverlapped                  //指向OVERLAPPED结构的指针) ;

lpOverlapped:如果文件是用FILE_FLAG_OVERLAPPED属性创建的,则需要此结构;如果文件是用FILE_FLAG_OVERLAPPED属性打开的,则参数lpOverlapped不为NULL,它指向一个OVERLAPPED结构。如果文件是用FILE_FLAG_OVERLAPPED属性创建且参数lpOverlapped为NULL,则该函数不能正确报告读操作是否完成。

如果文件用FILE_FLAG_OVERLAPPED属性打开且参数lpOverlapped不为NULL,则读操作从OVERLAPPED结构中指定的位置开始,且ReadFile( )函数在读操作完成之前返回。此时ReadFile( )返回FALSE,并且GetLastError( )函数返回ERROR_IO_PENDING,即执行读文件操作的进程被挂起,当读操作完成时,进程才继续执行。在OVERLAPPED结构中指定的事件被设置为读操作完成的发送信号状态。

如果文件不用FILE_FLAG_OVERLAPPED属性打开且参数lpOverlapped不为NULL,则读操作从OVERLAPPED结构中指定的位置开始,操作完成时ReadFile( )函数返回。

返回值:

  1. 如果函数调用成功,则返回值为非0值。
  2. 如果返回非0值,且读出的字节数为0,则说明执行读操作时文件的指针出界,此时调用GetLastError( )函数,可得到返回值ERROR_HANDLE_EOF。但若文件用FILE_FLAG_OVERLAPPED属性打开且参数lpOverlapped不为NULL,则ReadFile( )函数返回为FALSE。
  3. 如果函数调用失败,则返回值为0。若要得到更多的错误信息,可调用函数GetLastError( )。

用法举例:

//下面的例子说明如何测试异步读操作的文件结尾。
//设置 OVERLAPPED结构
gOverLapped.Offset    =0;
gOverLapped.OffsetHigh=0;
gOverLapped.hEvent    =NULL;
//执行异步读操作
bResult = ReadFile(hFile, &inBuffer, nBytesToRead, &nBytesRead, &gOverlapped);
//异步读不成功,进程挂起
if ( !bResult)
{  //处理错误码switch (dwError = GetLastError( )){  case ERROR_HANDLE_EOF:{//文件出界处理}case ERROR_IO_PENDING:{//异步I/O进行中//做其他事……GoDoSomethingElse( );//检查异步读结果bResult = GetOverlappedResult( hFile, &gOverlapped, &nBytesRead, FALSE) ;//若不成功if ( !bResult ){   //处理错误代码switch (dwError = GetLastError( ) ){case ERROR_HANDLE_EOF:{  //异步操作期间达到文件尾}//处理其他错误码}}}// end case//处理其他错误码}//end switch
}// end if

写文件

函数WriteFile ( ) 将数据写入文件。函数在文件指针所指的位置完成写操作,写操作完成后,文件指针按实际写入的字节数来调整。

  • 函数原型
BOOL WriteFile(                           HANDLE hFile,                            // 要读的文件的句柄LPVOID lpBuffer,                         // 指向文件缓冲区的指针DWORD nNumberOfBytesToWrite,             // 从文件中要读取的字节数LPDWORD lpNumberOfBytesWritten,          // 指向从文件中要读取的字节数的指针LPOVERLAPPED lpOverlapped                // 指向 OVERLAPPED结构的指针) ;

返回值:

  1. 如果函数调用成功,则返回值为非0值。
  2. 如果函数调用失败,则返回值为0.若要得到更多的错误信息,可调用函数GetLastError().

关闭文件句柄

函数CloseHandle()关闭与文件相关的句柄,其作用与释放动态申请的内存空间类似,这样可以释放系统资源,使进程安全运行。

函数原型:

BOOL CloseHandle(
HANDLE hObject
);

参数说明:

  • hObject:已打开对象的句柄

返回值:

  1. 如果函数调用成功,则返回值为非0值。
  2. 如果函数调用失败,则返回值为0.若要得到更多的错误信息,可调用函数GetLastError()。

三、实验内容

(一)实验内容

  1. 建立一个函数,使用该函数将原文件source.txt中的内容读出。再写到目标文件overlapped.txt中去。
  2. 采用异步方式实现文件的读/写。

(二)主要代码

// File_OverLapped.cpp : Defines the entry point for the console application.
//#include "stdafx.h"
#include "File_OverLapped.h"#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
DWORD BufferSize = 1024;
char buf[1024];
/
// The one and only application objectCWinApp theApp;using namespace std;
void FileReadWrite_Overlapped(char* source,char* destination);int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{int nRetCode = 0;printf("Call FileReadWrite_Overlapped!\n");FileReadWrite_Overlapped("source.txt","overlapped.txt");return nRetCode;
}void FileReadWrite_Overlapped(char* source,char* destination)
{HANDLE handle_src,handle_dst;DWORD NumberOfByteRead,NumberOfByteWrite,Error;BOOL cycle;char *buffer;buffer=buf;OVERLAPPED overlapped;//建立文件handle_src=CreateFile(source,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_FLAG_NO_BUFFERING|FILE_FLAG_OVERLAPPED,NULL);handle_dst=CreateFile(destination,GENERIC_WRITE,NULL,NULL,CREATE_ALWAYS,NULL,NULL);if (handle_src==INVALID_HANDLE_VALUE||handle_dst==INVALID_HANDLE_VALUE){printf("File Create Fail!\n");exit(1);}cycle=TRUE;overlapped.hEvent = NULL;overlapped.Offset = -BufferSize;overlapped.OffsetHigh = 0;while (cycle){overlapped.Offset = overlapped.Offset+BufferSize;NumberOfByteRead=BufferSize;//读文件if (!ReadFile(handle_src,buffer,NumberOfByteRead,&NumberOfByteRead,&overlapped)){switch(Error = GetLastError()){case ERROR_HANDLE_EOF:        //若到文件尾cycle = FALSE;break;case ERROR_IO_PENDING:      //若进程挂起if(!GetOverlappedResult(handle_src,&overlapped,&NumberOfByteRead,TRUE)){printf("GetOverlappedResult!%d\n",GetLastError());exit(1);}break;default:break;}}if(NumberOfByteRead<BufferSize) cycle=FALSE;//写文件if(!WriteFile(handle_dst,buffer,NumberOfByteRead,&NumberOfByteWrite,NULL)) {printf("Write File Error!%d\n",GetLastError());exit(1);}}  //关闭文件句柄CloseHandle(handle_src);CloseHandle(handle_dst);
}

四、实验结果和总结

实验结果

  • 在File_NoBuffer目录下建立source.txt文件并输入内容
  • 运行实验,将source.txt的文件内容复制到overlapped.txt文件下,显示如下代码
  • 运行后,File_NoBuffer目录下建立了overlapped.txt文件,并显示如下内容

总结

该实验完成异步方式的文件读/写操作。先创建文件source.txt,然后反复从文件source.txt中读出数据块,并写到文件overlapped.txt中去,直到文件尾为止。由于要采用异步方式对文件进行操作,在使用函数CreateFile()建立文件时其参数dwFlagsAndAttributes选用FILE-FLAG_NO_BUFFERING| FILE-FLAG_OVERLAPPED。

实验九 使用异步方式实现文件读\写相关推荐

  1. 实验九:采用异步方式实现文件读/写

    一:实验目的 (1)了解Windows系统异步文件读/写的概念. (2)熟悉Windows系统文件读/写相关的API. (3)掌握采用异步方式实现文件读/写的相关参数设置. 二:实验准备知识:文件异步 ...

  2. IBM SPSS的Sav文件读/写

    本文只要介绍通过IBM提供的库读/写sav文件格式. 在github上有.net版本和python版本,本文主要介绍用C读写sav文件. 参考文档:Input-Output Module.pdf,该文 ...

  3. Python学习笔记:文件读/写方法汇总

    # ############# 文件操作方法# 重点常用方法标红# ############import time, sys # ########### 读文件 ################### ...

  4. 移动文件读/写指针----lseek

    头文件:#include<sys/types.h>.#include<unistd.h> 函数原型:off_t lseek(int fildes,off_t offset,in ...

  5. Numpy简易教程7——读/写文件

    读/写文件 NumPy的文件读/写主要有二进制的文件读/写和文件列表形式的数据读/写两种形式.学会读/写文件是利用NumPy进行数据处理的基础.NumPy提供了若干函数,可以把结果保存到二进制或文本文 ...

  6. python读文件的三种方式_Python|读、写Excel文件(三种模块三种方式)

    python读写excel的方式有很多,不同的模块在读写的讲法上稍有区别: 用xlrd和xlwt进行excel读写: 用openpyxl进行excel读写: import xlrd from xlut ...

  7. 操作系统实验一到实验九合集(哈工大李治军)

    操作系统实验 作者寄语 操作系统实验的学习是一个循序渐进的过程,初次看linux-0.11中的代码,看着满屏的汇编语言,确实头疼.但通过学习赵炯博士的Linux内核0.11完全注释,结合着王爽老师的汇 ...

  8. wemos D1 Mini (esp8266)实验九 --- blynk APP远程控制格力空调开机并显示温湿度DHT22

    物联网-wemos D1 Mini (esp8266)实验九 --- blynk APP远程控制格力空调开机并显示温湿度 概述 实验材料 硬件 硬件连接图 引脚连接对照表 Arduino端软件编写 测 ...

  9. c语言程序设计实验教程实验报告,C语言程序设计实验报告——实验九.doc

    C语言程序设计实验报告--实验九.doc 下载提示(请认真阅读)1.请仔细阅读文档,确保文档完整性,对于不预览.不比对内容而直接下载带来的问题本站不予受理. 2.下载的文档,不会出现我们的网址水印. ...

最新文章

  1. python 简单数据库_Python打造一个简单的本地数据库
  2. 做了表分区以后的数据库表,在使用程序进行修改操作时报异常。
  3. linux vi模式替换,linux基础命令之:vi模式下查找和替换
  4. Python str 函数 - Python零基础入门教程
  5. 面试题,你觉得XX和XX产品有何区别?
  6. 崛起于Springboot2.X之redis集群搭建(17)
  7. Altium AD20导入DXF/DWG文件,导入AutoCAD绘制的树莓派4B板框及图形
  8. POJ 1050 To the Max (最大子矩阵和)
  9. maven spring-mvc mybatis整合
  10. 好用的局域网共享工具有哪些?win10系统如何设置?
  11. cocos creator fgui 按钮事件
  12. wechart image标签
  13. 路由器桥接(WIFI无线中继)设置及摆放位置图解
  14. redit mysql_【Voten】基于Laravel实现的类似Reddit的实时社交论坛系统
  15. 哥德巴赫猜想(java)
  16. linux下syscall函数
  17. 拆解博朗一款剃须刀,质量真心差。德吹可以休已
  18. 机器学习 常见面试题 总结
  19. android音乐频谱解析
  20. 在GitHub,他们是怎么玩的? (转)

热门文章

  1. php校园学校宿舍管理系统 php毕业设计题目课题选题 php毕业设计项目作品源码(3)班主任和宿舍管理员功能
  2. pppoe协议和pppd源码分析
  3. html计算平方米,尺和平方米换算(尺与平方米换算计算器)
  4. 深度相机(八)--OpenNI及与Kinect for windows SDK的比较
  5. iDRAC 7 Enterp license
  6. matlab图片修复原理,图像修复 Region filling and object removal by exemplar-based image inpainting matlab实现...
  7. 乐观锁与悲观锁的生动举栗讲解
  8. OA系统有哪些功能?在企业中发挥怎样的作用?
  9. ThinkPHP6集成腾讯云、短信宝短信发送的工具类
  10. gh-ost —— GitHub Online DDL 工具使用详解