windows环境下32位汇编语言程序设计-第74节
按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
次操作的最后一个字节后面的位置,这样顺序读写文件就不必每次重新指定位置。读写指针可以被移动到文件的任意位置,以便满足随机存取的要求。
Windows操作系统中,文件操作沿用了这种句柄方式,保留了文件句柄和读写指针等概念,同时又根据Windows操作系统的新特征对文件I/O进行了很多的扩展,下面列出了Win32中文件函数经过扩展的一些功能:
● 文件函数的操作对象有了很大的扩展,除了普通的文件,对串口、磁盘设备、网络文件、控制台和目录等的操作都可以使用文件函数来完成。
● 支持异步文件操作,文件函数可以不必等待到操作完成才能返回。
● Windows是多用户的操作系统,可能发生多个程序同时对文件操作的现象,文件函数中增强了对共享和锁定的支持。
● 文件操作函数和内存映射文件函数配合可以实现将文件当做内存的一部分来存取的功能。
● 增加了拷贝文件和移动文件等函数来实现常用的功能。
另外,在文件的命名中有长短文件名之分,众所周知,DOS操作系统使用8。3结构的文件命名方式,在这种命名方式下,用文件名来简单地说明文件的用途显得比较困难,因为仅用8个字符是表达不了什么复杂的含义的。
而在长文件名系统中,文件名的长度可以长达255个字符,这样在文件名中就可以清晰地表达出文件的用途,长文件名在磁盘的目录区中占用了多个连续的目录项,其中的一个目录项用做8。3结构的短文件名,其他的目录项存放其他名字字符。在8。3文件名中不合法的一些字符,如小数点与空格等在长文件名中都可以使用,只有/ :*?〃|等9个字符不能用于长文件名。
长文件名需要文件系统的支持,从DOS到Windows,使用过的有FAT,VFAT,FAT32,NTFS与HPFS等多种文件系统,在这些文件系统中,只有FAT系统不支持长文件名。
各种操作系统对文件系统的支持是不同的。Windows 3。x和DOS操作系统一直使用的是文件分配表(FAT)系统;Windows 95开始使用扩展FAT文件系统(VFAT),FAT系统和VFAT系统都是16位的文件系统,也称为FAT16。Windows NT在支持FAT16的同时,还支持两种32位的文件系统:NT文件系统(NTFS)和高性能文件系统(HPFS),NTFS支持文件的安全性,能够指定谁能访问某一文件或目录和对它做什么操作。Windows 98在支持FAT16的同时,也支持32位的FAT文件系统(FAT32),但Windows 9x系列操作系统不支持NTFS和HPFS。Windows 2000则支持上面所列的所有文件系统。
那么在Win32的文件操作函数中,如何处理长、短文件名,又如何处理不同的文件系统呢?答案很简单:就是不要去考虑它们,不管要操作的文件名是长是短,不管文件位于什么样的文件系统中,只要指定了正确的文件名,文件操作函数就能正确地处理它。
10。2。2 创建和读写文件
在开始讨论文件I/O的函数之前,先来看一个例子,这是一个对文本文件中的英文单词进行统计的小程序WordCount,程序将文本文件读入并分析文件内容,最后将统计结果保存到记录文件中,比如对包含下面文本的文件进行统计,就会得到如图10。4所示的记录文件:
“He's one of my best friend; a very very good man and has a very very good job and their relationship used to be so charming and stable; but now changed。”
图10。4 WordCount程序的运行结果
为了实现程序的功能,除了读文本文件和写记录文件外(这部分在本节中逐步介绍),还要涉及如何设计程序的结构。虽然可以用一个比较笨的办法:首先读一个单词,将它保存在缓存区中并为它增加一个计数,以后每读到一个单词就和以前保存的所有单词比较一下,如果存在则增加计数,不存在则保存一个新单词,但这种办法随着数据的增长工作量会急剧增加,所以例子程序用了另外一种方法:就是用树型结构的办法。
如图10。5所示,树的每个结点中有个计数器,还有26个子结点指针,子结点指针根据单词中的下一个字母是A~Z分别指向不同的子结点,假如我们遇到一个单词“ver”,就为它创建4层结点,第1层结点中的第22个指针(代表V)指向第2层,第2层结点中的第5个指针(代表E)再指向第3层结点,同样第3层结点中第19个指针(代表R)指向第4层结点,并将第4层结点的计数中增加1表示遇到了一个“ver”单词。
如果遇到单词“very”,那么继续创建第5层结点,并将V…》E…》R结点下的第25个指针中(代表Y)指向这个第5层结点,同时将这个第5层结点的计数加1。
如果遇到一个单词“var”,那么在第2层结点中的A位置将出现一个分支指向另一个第2层结点。这样一来,数据树最大可能的深度就是单词的最大长度。
图10。5 WordCount程序中的内存结构
为结点定义了一个数据结构:
WORD_COUNT struct
lpLetter dd 26 dup (?)
dwCount dd ?
dwDepth dd ?
WORD_COUNT ends
结构中设置了26个指针用来指向下一层结点,分别代表下一个字母分别是A~Z的情况,如果没有下一个字母,则指针设置为NULL,dwCount字段用来计数。
每当程序遇到一个单词的开始字母,就从第1层结点开始处理,如果对应位置的指针已经存在,则继续移动下去,如果不存在,表示以前还没有遇到这样的单词,那么就新申请一块内存建立一个下层结点,依此顺序随着单词中的字母一层层处理下去,直到遇到单词结尾的时候在当前结点的计数上加1就可以了。
在输出结果的时候,程序用递归的方法遍历整个树,并将每个计数不是0的结点写到记录文件中。
这个程序灵活地使用了前面介绍的内存分配/释放函数,读者可以看到用汇编语言来处理比较复杂的数据结构也是比较方便的,源程序可以在所附光盘的Chapter10WordCount目录中找到。汇编源文件WordCount。asm的内容如下:
。386
。model flat; stdcall
option casemap :none
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
来源:电子工业出版社 作者:罗云彬 上一页 回书目 下一页
上一页 回书目 下一页
第10章 内存管理和文件操作
10。2 文 件 操 作(2)
; Include 文件定义
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
include windows。inc
include user32。inc
includelib user32。lib
include kernel32。inc
includelib kernel32。lib
include dlg32。inc
includelib dlg32。lib
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; Equ 等值定义
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
ICO_MAIN equ 1000
DLG_MAIN equ 100
IDC_FILE equ 101
IDC_BROWSE equ 102
WORD_COUNT struct
lpLetter dd 26 dup (?)
dwCount dd ?
dwDepth dd ?
WORD_COUNT ends
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; 数据段
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
。data?
hInstance dd ?
hWinMain dd ?
szFileName db MAX_PATH dup (?)
szBuffer db 4096 dup (?)
stWordCount WORD_COUNT
dwCount dd ?
dwOption dd ?
F_COUNTING equ 00000001h
F_FILEEND equ 00000002h
nst
szFileExt db '全部文件';0;'*。*';0;0
szLogExt db '。log';0
szErrOpenFile db '无法打开文件!';0
szErrCreateFile db '无法建立记录文件!';0
szFmtWord db '%5d (%3d‰) %s';0dh;0ah;0
szSuccees db '统计成功,请查看记录文件%s';0
szSucceesCap db '统计成功';0
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; 代码段
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
de
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; 遍历树并输出结果
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
_WalkTree proc _hFile;_lpWC;_lpsz
local @dwTemp
local @szWord'52':byte
pushad
mov esi;_lpWC
assume esi:ptr WORD_COUNT
。if 'esi'。dwDepth && 'esi'。dwCount
;********************************************************************
; 计算百分比并写入log文件
;********************************************************************
mov eax;'esi'。dwCount
mov ecx;1000
mul ecx
mov ecx;dwCount
。if ecx
div ecx
。else
mov eax;0
。endif
invoke wsprintf;addr szBuffer;
addr szFmtWord;'esi'。dwCount;eax;_lpsz
invoke lstrlen;addr szBuffer
mov ecx;eax
invoke WriteFile;_hFile;addr szBuffer;
ecx;addr @dwTemp;NULL
。endif
;********************************************************************
; 如果有下层结点则递归调用
;********************************************************************
mov @dwTemp;0
。while @dwTemp 《 26
mov ebx;@dwTemp
mov ebx;dword ptr 'esi+ebx*4'
。if ebx
invoke lstrcpy;addr @szWord;_lpsz
invoke lstrlen;addr @szWord
lea ecx;@szWord
add ecx;eax
mov eax;@dwTemp
add al;'a'
mov word ptr 'ecx';ax
invoke _WalkTree;_hFile;ebx;addr @szWord
。endif