10.4 文件操作程序

有关目录和顺序文件的操作在第8.3.6节中已有介绍和举例,本节主要介绍对记录文件的读写方法。记录文件是指文件中的每个分量是一个结构的文件,如:Fox系列数据库管理系统中的DBF文件,该文件除了文件头是由记录文件的整体信息和各字段描述信息之外,文件的主体内容就是由同一个结构组成的。

下面通过二个例子来介绍记录文件的读写方法。

例10.11 假设有一个简单的学生结构类型student,其包括:学号、姓名和年龄等信息,要求编写一个程序,该程序接受从键盘输入的学生记录信息,并把它们保存在文件students.dat之中。

解:
.MODEL SMALL, C
.486
student STRUCT
id DW ?
sname DB 10 DUP(?)
age DB ?
student ENDS
.DATA

fname

DB "Students.dat",0

msg1

DB "Id:$"

msg2

DB "Name:$"

msg3

DB "Age:$"

msg4

DB "Continue?$"

msg5

DB "Fail to create file$"

CRLF

DB 0AH, 0DH, "$"

buff

DB ?, ?, 11 DUP(?)

peason

STUDENT <>
.CODE
DispMsg PROC USES AX DX, Msg:PTR BYTE ;显示字符串Msg
…… ;参见例10.7
DispMsg ENDP
;程序功能:把字符串Data转化成数值,不考虑负数。当遇到非法字符时,则结束转换操作;
;入口参数:Data为字符串的首地址,Len为该字符串的长度;
;出口参数:数值存放在AX中。
GetData PROC USES BX CX SI, Len:BYTE, Data:PTR BYPE
XOR CX, CX
MOV CL, Len
MOV SI, Data
XOR AX, AX
XOR BX, BX
.REPEAT

MOV

BL, [SI]

SUB

BL, '0'

.BREAK .IF BL<0 || BL>9

;判断当前数值是否在0~9之间

IMUL

AX, 10

ADD

AX, BX

INC

SI
.UNTILCXZ
RET
GetData ENDP
;程序功能:读取指定长度的字符串,在输入前,显示有关输入内容的提示信息;
;入口参数:读入字符串的长度为Len,提示信息的首地址为MSG;
;出口参数:读入信息(字符串)存放缓冲区buff中。
GetInfo PROC  USES AX DX, Len:BYTE, Msg:PTR BYTE
INVOKE DispMsg, Msg ;显示提示信息
MOV AL, Len
MOV buff, AL
MOV AH, 0AH
LEA DX, buff
INT 21H
INVOKE DispMsg, ADDR CRLF ;显示回车、换行
RET
GetInfo ENDP
.STARTUP
MOV AX, DS
MOV ES, AX
LEA DX, fname
MOV CX, 20H
MOV AH, 3CH
INT 21H ;创建文件
.IF CARRY? ;若创建失败,则显示失败信息

INVOKE DispMsg, ADDR msg5

JMP over

.ENDIF
MOV BX, AX ;把句柄存入BX,为后面使用作准备
again:
INVOKE DispMsg, ADDR CRLF ;显示回车、换行
INVOKE GetInfo, 5, ADDR msg1 ;读取学号(假定学号为4位整数)
INVOKE GetData, 4, ADDR buff+2 ;把学号字符串转化成数值
MOV peason.id, AX ;把数值型学号存入学号字段
INVOKE GetInfo, 11, ADDR msg2 ;读取姓名(假定姓名为10个字符)
MOV CX, 10
MOV AL, ' '  
LEA DI, peason.sname
REP STOSB ;先置姓名字段为10个空格
MOV CL, buff+1
MOV SI, OFFSET buff+2
LEA DI, peason.sname
REP MOVSB ;把输入的姓名存入姓名字段
INVOKE GetInfo, 3, ADDR msg3 ;读取年龄(假定年龄为2位整数) 
INVOKE GetData, 2, ADDR buff+2 ;把年龄字符串转化成数值
MOV peason.age, AL ;把数值型年龄存入年龄字段
MOV CX, SIZE peason
LEA DX, peason
MOV AH, 40H
INT 21H ;把学生记录写入文件
INVOKE DispMsg, ADDR msg4 ;提示是否继续输入
MOV AH, 1
INT 21H
AND AL, 0DFH
CMP AL, 'Y' 
JZ again ;若按y或Y,则继续输入
MOV AH, 3EH
INT 21H
over:
.EXIT 0
END