ITEEDU

7.3.2 随机块读写功能

功能号: 27H
用 途: 随机读取出一组记录
参 数: DS:DX--打开的FCB首地址
调 用: CX--要读取的记录数
返 回: INT 21H
AL = 0--读到全部指定记录
AL = 1--已读到文件尾
AL = 2--记录溢出段
AL = 3--读出部分记录
CX = 实际读到的记录数

功能号: 28H
用 途: 随机写出一组记录
参 数: DS:DX--打开的FCB首地址
调 用: CX--要写出的记录数
返 回: INT 21H
AL = 0--写出全部的记录
AL = 1--磁盘已满
AL = 2--记录溢出段
CX = 实际写出的记录数

从给出的应用方法我们可以看到随机块存取与随机存取功能在使用上的区别就在于入口参数与返回的结果中要涉及记录个数,其余的基本一致。不过这里我有必要说明一下这两个功能的出错情况:

(1)如果这两个功能返回的错误码02H,则表明记录溢出了DTA所在段。不过这时可能已经读入或写出了一些记录,出现这种情况程序需要根据CX返回的数据判断究竟读入了多少记录。
(2)如果返回的错误码为00H,表明子功能正确执行,此时DOS会修改FCB中随机记录号、当前记录块号和当前记录号,使它们都指向下一个记录。
(3)如果随机块写功能写出0个记录,则DOS将不写出任何数据,但此时DOS要修正文件长度,使之增长或缩减到由随机记录域和记录长度域两者结合所指示的长度。这是个很有趣的现象,有时我们可以用此方法修改文件的长度,这在一些杀病毒程序中有应用。

下面的程序例给出了这两个功能的实际应用情况,注意程序是如何调整目的文件的长度的。跟踪的结果附在程序例后面:

FCBCOPY.ASM
 ;数据段定义同FCB7.ASM,此处省略
        CODE  SEGMENT
              ASSUME    CS:CODE
        MAIN  PROC      FAR
              MOV       AX,DATA	;初始化DS寄存器
              MOV       DS,AX
			
              MOV       AH,0FH	;打开"源文件"
              MOV       DX,OFFSET FCB1
              INT       21H
              OR        AL,AL	;"源文件"正确打开了吗?
              JNZ       ERR_EXIT	;若没有正确打开文件,转ERR_EXIT
              MOV       AH,0FH	;打开"目标文件"
              MOV       DX,OFFSET FCB2
              INT       21H
              OR        AL,AL	;"目标文件"正确打开了吗?
              JZ        SET_DTA	;若正确打开了文件,转SET_DTA
			
              MOV       AH,16H	;建立"目标文件"
              MOV       DX,OFFSET FCB2
              INT       21H
              OR        AL,AL	;正确建立了"目标文件"吗?
              JNZ       ERR_EXIT	;若文件没有正确建立,转ERR_EXIT
    SET_DTA:
              PUSH      DS	;暂存DS寄存器
              MOV       AX,CS	;将CS寄存器"拷贝"入DS寄存器
              MOV       DS,AX
              MOV       AH,1AH	;设置新的DTA
              MOV       DX,OFFSET BUFFER
              INT       21H
              POP       DS	;恢复DS寄存器
   READ_REC:
              MOV       AH,27H	;利用"随机块读"功能
              MOV       DX,OFFSET FCB1	;从"源文件"中一次
              MOV       CX,7	;读入7个记录
              INT       21H
              CMP       AL,03H	;是否读入了部分记录?
              JZ        WRITE	;若只读人入了一部分记录,转WRITE
              JMP       ERR_EXIT	;若发生了其它错误,转ERR_EXIT
      WRITE:
              MOV       AH,28H	;利用"随机块写"功能将读入的数据
              MOV       DX,OFFSET FCB2	;写入"目标文件"中
              INT       21H
              OR        AL,AL	;数据正确地写入了吗?
              JNZ       ERR_EXIT	;若写入不正确,转ERR_EXIT
			
              MOV       BX,OFFSET FCB1	;BX寄存器指向FCB1
              MOV       AX,WORD PTR [BX+10H]	;取得"源文件"的长度
              MOV       BX,OFFSET FCB2	;BX寄存器指向FCB2
              MOV       WORD PTR [BX+21H],AX	;设置FCB2的随机记录号等于源文件长度
              MOV       WORD PTR [BX+0EH],1	;设置FCB2的记录大小为1字节
              MOV       AH,28H	;利用"随机块写"功能
              MOV       DX,BX	;修改"目标文件"的长度
              XOR       CX,CX
              INT       21H
   ERR_EXIT:
              MOV       AH,10H	;关闭"目标文件"
              MOV       DX,OFFSET FCB2
              INT       21H
			
              MOV       AH,4CH	;结束进程
              INT       21H
        MAIN  ENDP
      BUFFER  LABEL     BYTE
        CODE  ENDS
              END       MAIN

以下是这个程序的跟踪结果:

C:\ASM\>DEBUG FCBCOPY.EXE [Enter]
g=0 3d[Enter]
AX=2703 BX=0000 CX=0006 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=15F1 ES=15E1 SS=15F1 CS=15F6 IP=003D NV UP EI PL ZR NA PE NC
15F6:003D 3C03 CMP AL,03

执行随机块读功能,可以看到AL寄存器返回错误码03H,说明DOS没有读到完整的7个记录,只读到了6个记录。你可以列出DTA中的内容观察一下,看看是否读入了完整的CONFIG文件。

g=3d 4b[Enter]
AX=2800 BX=0000 CX=0006 DX=0025 SP=0000 BP=0000 SI=0000 DI=0000
DS=15F1 ES=15E1 SS=15F1 CS=15F6 IP=004B NV UP EI PL ZR NA PE NC
15F6:004B 0AC0 OR AL,AL

随机块写功能正常地执行了,有6个记录写入目的文件中,我们现在看看目的文件的长度是多少:

-d25 4a[Enter]
15F1:0020 03 43 4F-4E 46 49 47 20 20 54 58?					.CONFIG?TX
15F1:0030 54 00 00 80 00 00 03 00-00 54 21 94 4B 40 02 02 	T........T!.K@..
15F1:0040 59 07 60 B8 0F 06 06 00-00 00 00 					Y.`........

文件长度为300H字节,比实际长度667字节要大,所以我们需要调整一下目的文件的长度。在前面我们曾经用直接修改FCB中文件长度数值的方法改变文件长度,这种方法不太好,现在我们将使用随机块写功能调整文件长度:

g=4b 68[Enter]
AX=2800 BX=0025 CX=0006 DX=0025 SP=0000 BP=0000 SI=0000 DI=0000
DS=15F1 ES=15E1 SS=15F1 CS=15F6 IP=0068 NV UP EI PL ZR NA PE NC
15F6:0068 B410 MOV AH,10

调整的方法也不难,首先设置目标文件的随机记录号等于源文件的长度,并且将目标文件的记录长度设为1字节,然后我们向目标文件中写入0个记录,这样就可以修改目标文件的长度。

-d25 4a[Enter]
15F1:0020?03 43 4F-4E 46 49 47 20 20 54 58?.CONFIG?TX
15F1:0030 54 05 00 01 00 9B 02 00-00 54 21 9D 4B 40 02 02 T........T!.K@..
15F1:0040 59 07 60 B8 0F 1B 9B 02-00 00 00 Y.`........

调整后文件长度为29BH,恰好等于源文件长度。注意一下FCB中还有哪些数据发生了变化。
执行完所有的程序,返回DOS,看一看当前目录下是否有CONFIG.TXT文件,并检查其内容。
通过这几个程序例我想大家对FCB的随机存取功能已经有了相当的了解。下一节我们将结束对FCB的讨论。