下面这个程序例演示了文件写入功能的应用方法,请大家注意一下这个程序是依据什么来判断文件中所有数据都处理完毕的:
data segment assume ds:data fname1 db 'config.txt',0 ;源文件名 fname2 db 'config.bak',0 ;目标文件名 buffer db 32 dup(0) ;文件读写缓冲区 handle1 dw ? ;保存源文件句柄 handle2 dw ? ;保存目标文件句柄 msg1 db 'Error!!!',0dh,0ah,24h msg2 db 'OK...',0dh,0ah,24h data ends code segment assume cs:code main proc far mov ax,data ;初始化DS寄存器 mov ds,ax mov dx,offset fname1 ;DX寄存器指向源文件名 mov ax,3d00h ;按"读取"方式打开源文件 int 21h jc abord ;若打开操作出错,转ABORD mov handle1,ax ;将源文件的句柄保存至内存 mov dx,offset fname2 ;DX寄存器指向目标文件名 mov ah,3ch ;准备建立目标文件 mov cx,0 ;文件属性为"普通" int 21h jc abord ;文件未能正确建立,转ABORD mov handle2,ax ;将目标文件句柄保存至内存 dup_loop: mov ah,3fh ;准备从文件中读取数据 mov cx,32 ;读入32个字节 mov dx,offset buffer ;DX指向数据缓冲区 mov bx,handle1 ;从源文件中读取 int 21h jc abord ;若未能正确读入数据,转ABORD mov cx,ax ;CX寄存器置入实际读入的字节数 mov ah,40h ;准备写入文件 mov bx,handle2 ;写入目标文件中 int 21h jc abord ;若数据未能正确写入文件,转ABORD cmp cx,32 ;处理的数据够32个字节吗? jz dup_loop ;若处理的数据够32字节,转DUP_LOOP继续 mov ah,3eh ;关闭源文件 mov bx,handle1 int 21h mov bx,handle2 ;关闭目标文件 int 21h mov dx,offset msg2 ;显示字符串MSG2 mov ah,9 int 21h jmp exit ;转EXIT结束进程 abord: mov dx,offset msg1 ;输出字符串MSG1 mov ah,9 int 21h exit: mov ah,4ch ;结束进程 int 21h main endp code ends end main
通过这个程序我们可以看到写入功能40H的调用方法与3FH功能大同小异。这个程序每次处理32字节数据,依据DOS在AX寄存器返回的字节数判断是否处理完所有数据。它还演示了3CH功能的用法,除此之外没有什么更多特殊的地方。当然,有一点还要提醒大家,那就是不要忘记使用3EH功能关闭文件确实保证数据存入磁盘。
我们的学习好象变得越来越平淡了,新问题似乎变得少了,可能这就是一般所说的"书越念越浅"吧。实际上我所要讲解的东西也确实是越来越少,大家通过这一段的学习,对汇编语言的特点和学习方法已有了一定的了解,很多问题不用我说大家自然知道如何应用DEBUG之类的工具软件去分析研究。当然,概念性的内容还是要仔细讨论的,比如程序TYPEFILE.ASM所反映出的问题:
HANDLE2 equ 02h data segment assume ds:data fname1 db 'config.txt',0 ;将处理的文件名 buffer db 32 dup(0) ;文件缓冲区 handle1 dw ? ;保存文件句柄 msg1 db 'Error!!!',0dh,0ah,24h ;出错信息 data ends code segment assume cs:code main proc far mov ax,data ;初始化DS寄存器 mov ds,ax mov dx,offset fname1 ;DX寄存器指向ASCIIZ串 mov ax,3d00h ;准备按"读取"方式打开文件 int 21h jc abord ;若文件未能正确打开,转ABORD mov handle1,ax ;保存文件句柄 disp_loop: mov ah,3fh ;准备从文件中读取数据 mov cx,32 ;读入32字节 mov dx,offset buffer ;DX寄存器指向文件缓冲区 mov bx,handle1 ;从"CONFIG.SYS"中读入 int 21h jc abord ;数据未正确读入,转ABORD mov cx,ax ;CX寄存器置入实际读入的字符数 mov ah,40h ;准备将刚读入的数据写出 mov bx,HANDLE2 ;BX置入一个特殊的文件句柄 int 21h jc abord ;若数据未能正确写出,转ABORD cmp cx,32 ;处理的数据够32个字节吗? jz disp_loop ;若够32个字节,转DISP_LOOP继续执行 mov ah,3eh ;关闭文件"CONFIG.SYS" mov bx,handle1 int 21h jmp exit ;转EXIT结束进程 abord: mov dx,offset msg1 ;输出错误信息 mov ah,9 int 21h exit: mov ah,4ch ;结束进程 int 21h main endp code ends end main
这是一个不寻常的程序,它的特殊性就在于使用了"不寻常"的文件句柄。还记得前面我们讨论文件句柄时所遗留的那个问题吗?我们打开的第一个文件的句柄号是05H而不是00H,之所以这样是因为句柄号00H-04H已经被占用了。而且更为特殊的是这五个句柄不是赋予五个文件的,而是赋予五种硬件设备。这听上去好象越来越乱了,文件和硬件设备竟然又出现了某种联系,实在让人搞不明白。我想若要弄清楚这个问题,我们还是要从一些实际现象出发。