Windows核心编程学习笔记(20)--同步设备I/O与异步设备I/O1
2012-11-14 20:49
459 查看
Drecik学习经验分享
转载请注明出处:/article/3712389.html
根据上述表格打开一个设备后获得一个用来标志设备的句柄,可以将该句柄传给其他函数来与设备进行通信。
例如:调用SetCommConfig设置串口的波特率,调用SetMailslotInfo设置一个超时值。
完成操作后要使用CloseHandle关闭句柄,特殊的套接字使用closesocket关闭。
如果有一个设备句柄可以使用GetFileType传入设备句柄来获得设备的类型,返回值为:
FILE_TYPE_UNKNOW:位置类型
FILE_TYPE_DISK:磁盘文件
FILE_TYPE_CHAR:字符文件,一般说是一个并口设备或控制台
FILE_TYPE_PIPE:命名管道或匿名管道
dwDesiredAccess:指定何种方式和设备进行传输,常用的有:
0:不允许读取设备或向设备写入,只允许改变设备的配置
GENERIC_READ:允许只读访问
GENERIC_WRITE:允许只写访问
GENERIC_READ | GENERIC_WRITE:读写访问
dwShareMode:指定设备的共享特权,当我们打开设备之后并在关闭该句柄之前,该参数可以控制其他CreateFIle对该设备的打开,常用参数有:
0:独占对设备的访问
FILE_SHARE_READ:允许只读打开该设备
FILE_SHARE_WRITE:允许只写打开该设备
FILE_SHARE_READ | FILE_SHARE_WRITE:允许读写打开该设备
FILE_SHARE_DELETE:对文件而言,允许删除,当有操作将文件删除,则先标记,当该文件全部的句柄关闭后,将删除该文件
lpSecurityAttributes:安全属性,设置是否可以被继承
dwCreationDisposition:通常对文件而言最用大点,打开设备只能指定OPEN_EXISTING参数,常用参数有:
CREATE_NEW:创建一个新文件,如果存在则失败
CREATE_ALWAYS:无论是否存在,创建一个新文件
OPEN_EXISTING:打开以后文件或设备,不存在则失败
OPEN_ALWAYS:打开一个以后文件,不存在则创建新文件
TRUNCATE_EXISTING:打开已有文件,并将文件大小截断为0,不存在则失败
dwFlagsAndAttributes:设置一些标志来微调设备之间的通信,如果是文件,还能设置文件属性。当最后一个参数hTemplateFile为NULL时才可用,常用的参数有,还有其他属性请参考MSDN:
1. 高速缓存标志
FILE_FLAG_NO_BUFFER:标志在访问文件的时候不要使用任何数据缓存,读大文件的时候为了防止读取失败,需要设置该标志
FILE_FLAG_SEQUENTIAL_SCAN:标志将要顺序读取文件,该种情况下,系统从文件中读取的数据流会超过我们需要的数量,减少访问次数
FILE_FLAG_RANDOM_ACCESS:标志不要提前读取文件数据
FILE_FLAG_THROUGH:标志禁止对文件写入操作进行缓存以减少数据丢失的可能性,每次写入文件都直接写入到磁盘
2. 其他标志
FILE_FLAG_DELETE_ON_CLOSE:标志所有句柄关闭后将删除文件,通常和文件属性标志中的FILE_ATTRUBUTE_TEMPORARY一起使用
FILE_FLAG_BACKUP_SEMANTICS:一般用于备份和恢复软件,也可以使用该标志来打开一个目录句柄
FILE_FLAG_POSIX_SEMANTICS:标志打开或创建文件时以徐芬大小写的方式查找文件名
FILE_FLAG_OPEN_REPARSE_POINT:标志忽略文件的冲解析属性,不推荐使用
FILE_FLAG_OPEN_NO_RECALL:标志系统不要将文件内容从脱机存储器回复到联机存储器
FILE_FLAG_OVERLAPPED:标志想要以异步方式来访问设备
3. 文件属性标志
FILE_ATTRIBUTE_ARCHIVE:标志文件是一个存档文件,即待备份或待删除,默认为该标志
FILE_ATTRIBUTE_ENCRYPTED:标志文件是经过加密的
FILE_ATTRIBUTE_HIDDEN:标志文件是隐藏的
FILE_ATTRIBUTE_NORMAL:没有其他属性,只有单独使用的时候,这个标志才有效
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED:标志内容索引服务不会对文件进行索引
FILE_ATTRIBUTE_OFFLINE:标志文件虽然存在,但文件已经被转移到脱机存储器中
FILE_ATTRIBUTE_READONLY:标志文件是只读的,不能写入或删除文件
FILE_ATTRIBUTE_SYSTEM:标志文件是操作系统的一部分或专供操作系统使用
FILE_ATTRIBUTE_TEMPORARY:标志文件数据只会使用一小段时间,文件系统会尽量将文件数据保存在内存中而不是硬盘
hTemplateFile:既可以标识一个已经打开的文件的句柄,也可以为NULL,当不为NULL时,会忽略dwFlagsAndAttributes所有属性,使用hTemplateFile所标识的文件属性,hTemplateFile必须是使用GENERIC_READ打开的文件,如果CreateFile要打开已有的文件(而不是创建文件),那么它会忽略hTemplateFile参数
取得文件大小
最简单是使用GetFileEx来获取:
第二种是使用GetCompressedFileSize,返回的是文件的物理大小,而GetFileSizeEx返回的是逻辑大小,例如假设一个文件100KB,压缩后85KB,则逻辑大小为100KB,而物理大小为85KB:
设置文件指针的位置
文件内核对象有一个文件指针,是一个64位偏移量,表示下次在哪里读取或者写入。
每个文件内核对象都有自己的文件指针,通过DuplicateHandle复制的文件句柄也共用一个文件指针
如果需要随机访问文件,则我们可以调用SetFilePointerEx来改变文件指针:
最后一个参数可以有如下值:
FILE_BEGIN:文件对象的文件指针将被设为liDistanceToMove参数指定的值,此时该参数是一个无符号64位值
FILE_CURRENT:文件对象的文件指针将与liDistanceToMove参数相加,此时该参数是一个有符号64位值
FILE_END:文件对象的指针被设置为文件的逻辑大小加上liDistanceToMove参数,此时该参数是一个有符号64位值
最后文件指针的操作需要注意下面几项:
将文件指针的值设为超过大小是正当操作,除非是在该位置写入或者调用SetEndOfFile,否则这样做不会增加文件实际大小
如果SetFilePointerEx操作的文件是使用FILE_FLAG_NO_BUFFER打开,则文件指针只能被设置为扇区大小的整数倍
Windows没有提供GetFilePointerEx函数,但是可以将liDistanceToMove参数设置为0,并设置FILE_CURRENT来获得当前指针
设置文件尾
通常在文件关闭的时候,系统会负责设置文件尾,当我们需要将文件强制变的更大或更小,我们可以使用SetEndOfFile自己设置文件尾,例如下面代码:
另外一个常用函数是FlushFileBuffers,该函数强制将与hFile参数表示的设备相关联的所有缓存数据写入设备。
Windows Visita及以上提供了同步I/O的取消操作:
当进行同步I/O时,会阻塞当前调用的线程,直到操作返回,当线程正在因为进行同步I/O而挂起时,我们可以使用CancelSynchronousIo来取消同步I/O操作:
如果指定的线程是因为同步I/O而挂起,调用该函数后可以将线程唤醒,此时同步I/O就会调用失败,该函数返回TRUE
如果调用线程不是因为同步I/O而挂起时,则该函数返回FLASE
转载请注明出处:/article/3712389.html
1. 打开和关闭设备
首先看下Windows常用的设备和打开他们的函数:根据上述表格打开一个设备后获得一个用来标志设备的句柄,可以将该句柄传给其他函数来与设备进行通信。
例如:调用SetCommConfig设置串口的波特率,调用SetMailslotInfo设置一个超时值。
完成操作后要使用CloseHandle关闭句柄,特殊的套接字使用closesocket关闭。
如果有一个设备句柄可以使用GetFileType传入设备句柄来获得设备的类型,返回值为:
FILE_TYPE_UNKNOW:位置类型
FILE_TYPE_DISK:磁盘文件
FILE_TYPE_CHAR:字符文件,一般说是一个并口设备或控制台
FILE_TYPE_PIPE:命名管道或匿名管道
2. 细看CreateFile函数
就如上面表格中所示,CreateFile函数可以创建和打开磁盘文件还可以打开许多其他设备,打开失败返回INVALID_HANDLE_VALUE。HANDLE CreateFileW( LPCWSTR lpFileName, // 设备的类型或该设备的某个实例; DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile );
dwDesiredAccess:指定何种方式和设备进行传输,常用的有:
0:不允许读取设备或向设备写入,只允许改变设备的配置
GENERIC_READ:允许只读访问
GENERIC_WRITE:允许只写访问
GENERIC_READ | GENERIC_WRITE:读写访问
dwShareMode:指定设备的共享特权,当我们打开设备之后并在关闭该句柄之前,该参数可以控制其他CreateFIle对该设备的打开,常用参数有:
0:独占对设备的访问
FILE_SHARE_READ:允许只读打开该设备
FILE_SHARE_WRITE:允许只写打开该设备
FILE_SHARE_READ | FILE_SHARE_WRITE:允许读写打开该设备
FILE_SHARE_DELETE:对文件而言,允许删除,当有操作将文件删除,则先标记,当该文件全部的句柄关闭后,将删除该文件
lpSecurityAttributes:安全属性,设置是否可以被继承
dwCreationDisposition:通常对文件而言最用大点,打开设备只能指定OPEN_EXISTING参数,常用参数有:
CREATE_NEW:创建一个新文件,如果存在则失败
CREATE_ALWAYS:无论是否存在,创建一个新文件
OPEN_EXISTING:打开以后文件或设备,不存在则失败
OPEN_ALWAYS:打开一个以后文件,不存在则创建新文件
TRUNCATE_EXISTING:打开已有文件,并将文件大小截断为0,不存在则失败
dwFlagsAndAttributes:设置一些标志来微调设备之间的通信,如果是文件,还能设置文件属性。当最后一个参数hTemplateFile为NULL时才可用,常用的参数有,还有其他属性请参考MSDN:
1. 高速缓存标志
FILE_FLAG_NO_BUFFER:标志在访问文件的时候不要使用任何数据缓存,读大文件的时候为了防止读取失败,需要设置该标志
FILE_FLAG_SEQUENTIAL_SCAN:标志将要顺序读取文件,该种情况下,系统从文件中读取的数据流会超过我们需要的数量,减少访问次数
FILE_FLAG_RANDOM_ACCESS:标志不要提前读取文件数据
FILE_FLAG_THROUGH:标志禁止对文件写入操作进行缓存以减少数据丢失的可能性,每次写入文件都直接写入到磁盘
2. 其他标志
FILE_FLAG_DELETE_ON_CLOSE:标志所有句柄关闭后将删除文件,通常和文件属性标志中的FILE_ATTRUBUTE_TEMPORARY一起使用
FILE_FLAG_BACKUP_SEMANTICS:一般用于备份和恢复软件,也可以使用该标志来打开一个目录句柄
FILE_FLAG_POSIX_SEMANTICS:标志打开或创建文件时以徐芬大小写的方式查找文件名
FILE_FLAG_OPEN_REPARSE_POINT:标志忽略文件的冲解析属性,不推荐使用
FILE_FLAG_OPEN_NO_RECALL:标志系统不要将文件内容从脱机存储器回复到联机存储器
FILE_FLAG_OVERLAPPED:标志想要以异步方式来访问设备
3. 文件属性标志
FILE_ATTRIBUTE_ARCHIVE:标志文件是一个存档文件,即待备份或待删除,默认为该标志
FILE_ATTRIBUTE_ENCRYPTED:标志文件是经过加密的
FILE_ATTRIBUTE_HIDDEN:标志文件是隐藏的
FILE_ATTRIBUTE_NORMAL:没有其他属性,只有单独使用的时候,这个标志才有效
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED:标志内容索引服务不会对文件进行索引
FILE_ATTRIBUTE_OFFLINE:标志文件虽然存在,但文件已经被转移到脱机存储器中
FILE_ATTRIBUTE_READONLY:标志文件是只读的,不能写入或删除文件
FILE_ATTRIBUTE_SYSTEM:标志文件是操作系统的一部分或专供操作系统使用
FILE_ATTRIBUTE_TEMPORARY:标志文件数据只会使用一小段时间,文件系统会尽量将文件数据保存在内存中而不是硬盘
hTemplateFile:既可以标识一个已经打开的文件的句柄,也可以为NULL,当不为NULL时,会忽略dwFlagsAndAttributes所有属性,使用hTemplateFile所标识的文件属性,hTemplateFile必须是使用GENERIC_READ打开的文件,如果CreateFile要打开已有的文件(而不是创建文件),那么它会忽略hTemplateFile参数
3. 使用文件设备
Windows使用64位的值来管理文件,所以理论上能处理的文件可以达到16EB取得文件大小
最简单是使用GetFileEx来获取:
BOOL GetFileSizeEx( HANDLE hFile, // 文件句柄; PLARGE_INTEGER lpFileSize // 用来返回文件大小的64位值; );
第二种是使用GetCompressedFileSize,返回的是文件的物理大小,而GetFileSizeEx返回的是逻辑大小,例如假设一个文件100KB,压缩后85KB,则逻辑大小为100KB,而物理大小为85KB:
DWORD // 返回文件大小的低位; GetCompressedFileSizeW( LPCWSTR lpFileName, // 文件名; LPDWORD lpFileSizeHigh // 返回文件大小的高位; );
设置文件指针的位置
文件内核对象有一个文件指针,是一个64位偏移量,表示下次在哪里读取或者写入。
每个文件内核对象都有自己的文件指针,通过DuplicateHandle复制的文件句柄也共用一个文件指针
如果需要随机访问文件,则我们可以调用SetFilePointerEx来改变文件指针:
BOOL SetFilePointerEx( HANDLE hFile, // 文件句柄; LARGE_INTEGER liDistanceToMove, // 想要把指针移动多少字节; PLARGE_INTEGER lpNewFilePointer, // 返回新的指针位置,可以为NULL; DWORD dwMoveMethod // 指定第二个参数相对移动的起始位置; );
最后一个参数可以有如下值:
FILE_BEGIN:文件对象的文件指针将被设为liDistanceToMove参数指定的值,此时该参数是一个无符号64位值
FILE_CURRENT:文件对象的文件指针将与liDistanceToMove参数相加,此时该参数是一个有符号64位值
FILE_END:文件对象的指针被设置为文件的逻辑大小加上liDistanceToMove参数,此时该参数是一个有符号64位值
最后文件指针的操作需要注意下面几项:
将文件指针的值设为超过大小是正当操作,除非是在该位置写入或者调用SetEndOfFile,否则这样做不会增加文件实际大小
如果SetFilePointerEx操作的文件是使用FILE_FLAG_NO_BUFFER打开,则文件指针只能被设置为扇区大小的整数倍
Windows没有提供GetFilePointerEx函数,但是可以将liDistanceToMove参数设置为0,并设置FILE_CURRENT来获得当前指针
设置文件尾
通常在文件关闭的时候,系统会负责设置文件尾,当我们需要将文件强制变的更大或更小,我们可以使用SetEndOfFile自己设置文件尾,例如下面代码:
HANDLE hFile = CreateFile( TEXT("Test.txt"), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL ); // 设置文件指针; LARGE_INTEGER li = {0}; li.LowPart = 1024*1024; SetFilePointerEx( hFile, li, NULL, FILE_BEGIN ); // 强制将文件设置为1MB; SetEndOfFile(hFile);
4. 执行同步设备I/O
最常用对设备数据进行的操作就是读和写,使用ReadFile和WriteFile来实现(不单单指对文件):// 只能用于GENERIC_READ标志打开的设备; BOOL ReadFile( HANDLE hFile, // 设备句柄; LPVOID lpBuffer, // 读取缓冲区; DWORD nNumberOfBytesToRead, // 读取的字节数; LPDWORD lpNumberOfBytesRead, // 返回实际读取的字节数; LPOVERLAPPED lpOverlapped // 用来设置异步访问,同步访问必须为NULL; ); // 只能用于GENERIC_WRITE标志打开的设备; BOOL WriteFile( HANDLE hFile, // 设备句柄; LPCVOID lpBuffer, // 写入缓冲区; DWORD nNumberOfBytesToWrite, // 写入的字节数; LPDWORD lpNumberOfBytesWritten, // 返回实际写入的字节数; LPOVERLAPPED lpOverlapped // 用来设置异步访问,同步访问必须为NULL; );
另外一个常用函数是FlushFileBuffers,该函数强制将与hFile参数表示的设备相关联的所有缓存数据写入设备。
Windows Visita及以上提供了同步I/O的取消操作:
当进行同步I/O时,会阻塞当前调用的线程,直到操作返回,当线程正在因为进行同步I/O而挂起时,我们可以使用CancelSynchronousIo来取消同步I/O操作:
BOOL CancelSynchronousIo( HANDLE hThread // 线程句柄; );hThread是OpenThread打开的时候必须包括THREAD_TERMINATE访问权限
如果指定的线程是因为同步I/O而挂起,调用该函数后可以将线程唤醒,此时同步I/O就会调用失败,该函数返回TRUE
如果调用线程不是因为同步I/O而挂起时,则该函数返回FLASE
相关文章推荐
- Windows核心编程学习笔记(21)--同步设备I/O与异步设备I/O2
- 应用程序对设备 + IRP 的同步异步学习
- 《Windows核心编程系列》十谈谈同步设备IO与异步设备IO之异步IO
- 第10章 同步设备I/O和异步设备I/O(1)_常见设备及CreateFile函数
- <<Windows核心编程(第五版)>>第十章同步设备I/O与异步设备I/O:10.5接收I/O请求完成通知
- 第十章 同步设备I/O和异步设备I/O
- 应用程序对设备 + IRP 的同步异步学习
- 《Windows核心编程》学习笔记(10)– 同步设备I/O与异步设备I/O
- 第十章:同步设备IO与异步设备IO
- 字符设备驱动--异步通知、同步互斥阻塞
- 同步设备IO与异步设备IO
- 同步和异步设备I/O
- 同步和异步设备I/O(Synchronous and asynchronous device IO)
- 第十章:同步设备I/O与异步设备I/O
- 第十章:同步设备I/O与异步设备I/O(二)
- 《Windows Via C/C++》学习之同步设备I/O与异步设备I/O
- 十、同步设备I/O与异步设备I/O(I/O完成端口)
- windows 核心编程之 10 同步设备IO与异步设备IO
- 《Windows核心编程 5th》部分读书笔记----第10章 同步设备I/O与异步设备I/O
- 对设备的同步、异步访问