ITEEDU

下面这个程序例演示了文件写入功能的应用方法,请大家注意一下这个程序是依据什么来判断文件中所有数据都处理完毕的:

DUP.ASM
        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所反映出的问题:

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已经被占用了。而且更为特殊的是这五个句柄不是赋予五个文件的,而是赋予五种硬件设备。这听上去好象越来越乱了,文件和硬件设备竟然又出现了某种联系,实在让人搞不明白。我想若要弄清楚这个问题,我们还是要从一些实际现象出发。