WIN32汇编语言教程:第10章 内存管理和文件操作 · 10.2 文件操作(6)
如果读取文件失败,则函数返回0,成功则函数返回非0值。当函数返回非0值而lpNumberOfBytesRead中返回的已读取字节数却是0时,表示已经读到了文件尾。在例子中读文件使用:
invoke ReadFile,@hFile,addr szBuffer,sizeof szBuffer,addr @dwBytesRead,0
这样读出的字节数保存在@dwBytesRead变量中,然后根据@dwBytesRead中的计数循环处理文件内容。
向文件写数据的函数WriteFile的使用方法与ReadFile函数类似:
invoke WriteFile,hFile,lpBuffer,nNumberOfBytesToWrite,\ lpNumberOfBytesWritten,lpOverlapped
同样,hFile参数是文件句柄;lpBuffer指向一个缓冲区,缓冲区中包含有要写入文件的数据;nNumberOfBytesToWrite参数指定需要写入的字节数,函数在lpNumberOfBytesRead指出的dword类型变量中返回成功写入的字节数。
当用WriteFile写文件的时候,写入的数据可能被Windows暂时保存在内部的高速缓存中,等合适的时候再一并写入磁盘;如果WriteFile函数写的是串口或者一个管道,大块数据同样是暂时保留在缓冲区中等待逐步发送出去。虽然这些数据一般不会丢失,但并不能保证它们总是不会丢失的,比如在文件关闭之前计算机断电了,或者数据发送之前对端断开了串口连接等情况。
如果一定要保证数据正确地写入了或者传输了,可以强制使用FlushFileBuffers函数来清空数据缓冲区,FlushFileBuffers函数的参数仅是一个文件句柄:
invoke FlushFileBuffers,hFile
如果hFile代表一个文件,函数会将所有缓冲区的数据马上写入文件;如果hFile代表一个串口,那么函数发送缓冲区中所有的数据;如果hFile代表一个管道的话,函数一直等待直到管道的另一方读取全部数据。总之这个函数执行成功的话,就能够保证所有的数据已经被传送。如果函数执行成功,返回值是非0值,执行失败则函数返回0。
4. 文件的共享
如果对文件数据的一致性要求比较高,为了防止程序在写入的过程中其他进程刚好在读取写入区域的内容,可以对已打开文件的某个部分进行加锁,加锁后可以防止其他进程对该区域进行读取或写入的操作。加锁和解锁使用LockFile和UnlockFile函数,读者也可以使用LockFileEx和UnlockFileEx函数,这两个函数可以以异步方式执行。
LockFile函数和UnlockFile函数的使用方法是:
invoke LockFile,hFile,dwFileOffsetLow,dwFileOffsetHigh,\
nNumberOfBytesToLockLow,nNumberOfBytesToLockHigh
invoke UnlockFile,hFile,dwFileOffsetLow,dwFileOffsetHigh,\
nNumberOfBytesToLockLow,nNumberOfBytesToLockHigh
dwFileOffsetLow和dwFileOffsetHigh参数组合起来指定了加锁区域的开始位置,dwNumberOfBytesToLockLow和dwNumberOfBytesToLockHight参数组合则指定加锁区域的大小,这两组参数都指定了一个64位的值,在Windows中,可以只使用低32位。
文件锁是排他性的,不能对一个区域重复加锁,两个不同的加锁区域也不能重叠;在对文件加锁和解锁的时候操作的区域也必须一一对应,对一个区域加锁后不能分几次对区域中的不同部分解锁,而必须一次全部解锁。
当程序读取一个文件的时候,如果文件有可能被其他进程加锁的话,那么在读取失败的时候就必须调用GetLastError函数来获取失败的原因,如果失败的原因是因为锁定造成的共享错误的话,那么可以等待一段时间后继续读取。
10.2.3 查找文件
在DOS中可以使用int 21h中断的4eh和4fh功能查找一个目录中的指定文件,Win32中也可以进行类似的操作,方法是用两个函数分别实现查找第一个文件和继续查找文件的功能。
当要开始查找文件的时候,首先使用 FindFirstFile函数,如果函数执行成功,返回一个句柄hFindFile来对应这个寻找操作,接下来可以利用这个句柄循环调用FindNextFile函数继续查找其他文件,一直到FindNextFile函数返回失败为止,最后必须关闭hFindFile句柄。使用这几个函数查找文件的代码一般使用下面的结构:
invoke FindFirstFile,lpFindFile,lpFindFileData
.if eax != INVALID_HANDLE_VALUE
mov hFindFile,eax
.repeat
;处理本次找到的文件
invoke FindNextFile,hFindFile,addr lpFindFileData
.until eax == FALSE
invoke FindClose,hFindFile
.endif
如果FindFirstFile函数执行失败,则下面的循环就不必执行了,如果FindFirstFile执行成功,那么程序保存返回的hFindFile并开始一个 .repeat循环,使用 .repeat语句而不是.while的原因是.repeat构成的循环先执行循环体内的内容,这样第一次循环时首先处理FindFirstFile找到的文件,然后再根据FindNextFile执行的结果决定是否继续循环。在结束循环后,需要用FindClose函数将查找句柄关闭。
FindFirstFile的参数lpFindFile指向一个字符串,代表要寻找的文件名,如果文件名中不包含路径,那么在当前目录中查找文件,包含路径的话将在指定路径中查找。在文件名中可以用“*”或“?”通配符指定查找特定的文件。下面是文件名格式的几个例子:
c:\Windows\*.* ;在c:\Windows目录中查找所有文件
c:\Windows\System32\*.dll ;在c:\Windows\System32目录中查找所有dll文件
c:\Windows\System.ini ;在c:\Windows目录中查找System.ini文件
c:\Windows\a???.* ;在c:\Windows目录中查找所有以a开头的文件名 ;长度为4个字符的文件
Test.dat ;在当前目录查找Test.dat文件
*.* ;在当前目录查找所有文件
FindFirstFile函数和FindNextFile函数中的lpFindFileData参数则指向一个缓冲区,函数会在缓冲区中返回一个WIN32_FIND_DATA结构,结构中包括了Windows查找过程中临时使用的数据和找到的文件名与文件属性等数据。该结构的定义如下:
WIN32_FIND_DATA STRUCT
dwFileAttributes DWORD ? ;文件属性
ftCreationTime FILETIME <> ;文件的创建日期
ftLastAccessTime FILETIME <> ;文件的最后存取日期
ftLastWriteTime FILETIME <> ;文件的最后修改日期
nFileSizeHigh DWORD ? ;文件长度的高32位
nFileSizeLow WORD ? ;文件长度的低32位
dwReserved0 DWORD ? ;内部使用
dwReserved1 DWORD ? ;内部使用
cFileName BYTE MAX_PATH dup(?) ;本次找到的文件名
cAlternate BYTE 14 dup(?) ;文件的8.3结构的短文件名
WIN32_FIND_DATA ENDS
dwFileAttributes字段可以是下面取值的组合,通过这个字段可以检查找到的究竟是一个文件还是一个子目录,以及其他的文件属性:
● FILE_ATTRIBUTE_ARCHIVE——文件包含归档属性。
● FILE_ATTRIBUTE_COMPRESSED——文件和目录被压缩。
● FILE_ATTRIBUTE_DIRECTORY——找到的是一个目录。
● FILE_ATTRIBUTE_HIDDEN——文件包含隐含属性。
● FILE_ATTRIBUTE_NORMAL——文件没有其他属性。
● FILE_ATTRIBUTE_READONLY——文件包含只读属性。
● FILE_ATTRIBUTE_SYSTEM——文件包含系统属性。
● FILE_ATTRIBUTE_TEMPORARY——文件是一个临时文件。
cFileName字段中包括了找到的文件名,这个文件名中并不包含路径,仅文件名而已,如果需要全路径的文件名还需要由我们自己将它和路径字符串相连接。
在所附光盘中有一个全盘搜索的例子,一般杀毒软件都可以对指定目录或者盘符下的所有文件以及所有子目录下的文件做扫描,使用上面的文件查找函数可以很方便地完成全盘搜索的功能,源代码位于Chapter10\FindFile目录下。FindFile.asm文件的内容如下:
.386
.model flat, stdcall
option casemap :none
;####################################################################
; Include 文件定义
;####################################################################
include windows.inc
include user32.inc
includelib user32.lib
上页:第10章 内存管理和文件操作 · 10.2 文件操作(5) 下页:第10章 内存管理和文件操作 · 10.2 文件操作(7)