11 KiB
实验八:文件操作
一、基础性实验
1.1 实验目的
掌握DOS功能调用进行文件操作的方法,包括文件的创建、写入、读取和删除。
1.2 实验内容
程序 1:文件创建程序
使用功能号3CH创建新文件。
; 实验八-1: 文件创建程序
; 功能: 使用DOS功能号3CH创建新文件
; 说明: AL=00H表示普通文件属性
DATAS SEGMENT
FILENAME DB 'testfile.txt', 0 ; 要创建的文件名
HANDLE DW ? ; 文件句柄
ERR_MSG DB 'File creation error!', 0DH, 0AH, '$'
OK_MSG DB 'File created successfully!', 0DH, 0AH, '$'
DATAS ENDS
STACKS SEGMENT
DB 64 DUP(?)
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES, DS:DATAS, SS:STACKS
START:
MOV AX, DATAS
MOV DS, AX
; 创建文件
; AH = 3CH (创建文件功能号)
; AL = 00H (普通文件属性)
; DS:DX = 文件名地址
LEA DX, FILENAME
MOV AH, 3CH
MOV AL, 00H
INT 21H
; 检查是否成功 (CF=0表示成功)
JNC CREATE_SUCCESS
; 创建失败,显示错误信息
LEA DX, ERR_MSG
MOV AH, 09H
INT 21H
JMP PROGRAM_END
CREATE_SUCCESS:
; 保存文件句柄
MOV HANDLE, AX
; 显示成功信息
LEA DX, OK_MSG
MOV AH, 09H
INT 21H
PROGRAM_END:
MOV AH, 4CH
INT 21H
CODES ENDS
END START
说明:功能号3CH用于创建文件。如果文件已存在,则将其长度截断为0。文件属性通过AL寄存器设置:00H表示普通文件,01H表示只读,02H表示隐含,04H表示系统文件。
程序 2:文件写入程序
使用功能号40H向文件写入数据。
; 实验八-2: 文件写入程序
; 功能: 使用DOS功能号40H向文件写入数据
DATAS SEGMENT
FILENAME DB 'testfile.txt', 0
HANDLE DW ?
DATA_TO_WRITE DB 'Hello, Assembly!', 0DH, 0AH, '$'
DATA_LEN EQU $-DATA_TO_WRITE
ERR_MSG DB 'File write error!', 0DH, 0AH, '$'
OK_MSG DB 'Data written successfully!', 0DH, 0AH, '$'
DATAS ENDS
STACKS SEGMENT
DB 64 DUP(?)
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES, DS:DATAS, SS:STACKS
START:
MOV AX, DATAS
MOV DS, AX
; 创建文件
LEA DX, FILENAME
MOV AH, 3CH
MOV AL, 00H
INT 21H
JC WRITE_ERROR
MOV HANDLE, AX
; 写入文件内容 (功能号40H)
; AH=40H, BX=句柄, CX=字节数, DS:DX=缓冲区
MOV BX, HANDLE
LEA DX, DATA_TO_WRITE
MOV CX, DATA_LEN
MOV AH, 40H
INT 21H
JNC WRITE_SUCCESS
WRITE_ERROR:
LEA DX, ERR_MSG
MOV AH, 09H
INT 21H
JMP CLOSE_FILE
WRITE_SUCCESS:
LEA DX, OK_MSG
MOV AH, 09H
INT 21H
CLOSE_FILE:
MOV BX, HANDLE
MOV AH, 3EH
INT 21H
MOV AH, 4CH
INT 21H
CODES ENDS
END START
程序 3:文件读取程序
使用功能号3FH读取文件内容。
; 实验八-3: 文件读取程序
; 功能: 使用DOS功能号3FH读取文件内容
DATAS SEGMENT
FILENAME DB 'testfile.txt', 0
HANDLE DW ?
BUFFER DB 100 DUP(?)
ERR_MSG DB 'File open error!', 0DH, 0AH, '$'
READ_ERR_MSG DB 'File read error!', 0DH, 0AH, '$'
OK_MSG DB 'File read successfully!', 0DH, 0AH, '$'
CR_LF DB 0DH, 0AH, '$'
DATAS ENDS
STACKS SEGMENT
DB 64 DUP(?)
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES, DS:DATAS, SS:STACKS
START:
MOV AX, DATAS
MOV DS, AX
; 打开文件 (功能号3DH)
LEA DX, FILENAME
MOV AH, 3DH
MOV AL, 00H
INT 21H
JNC OPEN_SUCCESS
LEA DX, ERR_MSG
MOV AH, 09H
INT 21H
JMP PROGRAM_END
OPEN_SUCCESS:
MOV HANDLE, AX
; 读取文件内容 (功能号3FH)
MOV BX, HANDLE
LEA DX, BUFFER
MOV CX, 100
MOV AH, 3FH
INT 21H
JNC READ_SUCCESS
LEA DX, READ_ERR_MSG
MOV AH, 09H
INT 21H
JMP CLOSE_FILE
READ_SUCCESS:
MOV CX, AX
LEA DI, BUFFER
MOV AH, 02H
DISPLAY_LOOP:
MOV DL, [DI]
INT 21H
INC DI
LOOP DISPLAY_LOOP
LEA DX, CR_LF
MOV AH, 09H
INT 21H
LEA DX, OK_MSG
MOV AH, 09H
INT 21H
CLOSE_FILE:
MOV BX, HANDLE
MOV AH, 3EH
INT 21H
PROGRAM_END:
MOV AH, 4CH
INT 21H
CODES ENDS
END START
程序 4:文件删除程序
使用功能号41H删除文件。
; 实验八-4: 文件删除程序
; 功能: 使用DOS功能号41H删除文件
DATAS SEGMENT
FILENAME DB 'testfile.txt', 0
ERR_MSG DB 'File delete error!', 0DH, 0AH, '$'
OK_MSG DB 'File deleted successfully!', 0DH, 0AH, '$'
NO_FILE_MSG DB 'File does not exist!', 0DH, 0AH, '$'
DATAS ENDS
STACKS SEGMENT
DB 64 DUP(?)
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES, DS:DATAS, SS:STACKS
START:
MOV AX, DATAS
MOV DS, AX
; 删除文件 (功能号41H)
; AH=41H, AL=00H, DS:DX=文件名
LEA DX, FILENAME
MOV AH, 41H
MOV AL, 00H
INT 21H
JNC DELETE_SUCCESS
CMP AX, 02H
JE FILE_NOT_FOUND
LEA DX, ERR_MSG
MOV AH, 09H
INT 21H
JMP PROGRAM_END
FILE_NOT_FOUND:
LEA DX, NO_FILE_MSG
MOV AH, 09H
INT 21H
JMP PROGRAM_END
DELETE_SUCCESS:
LEA DX, OK_MSG
MOV AH, 09H
INT 21H
PROGRAM_END:
MOV AH, 4CH
INT 21H
CODES ENDS
END START
1.3 实验结果
程序运行后,文件创建、写入、读取和删除功能均正常工作。功能号3CH用于创建文件并将句柄返回到AX寄存器;功能号40H通过BX指定句柄进行数据写入;功能号3FH通过BX指定句柄进行数据读取,实际读取字节数返回到AX;功能号41H删除指定文件。所有操作通过CF标志位判断成功与否。
1.4 思考题
-
DOS功能调用中,文件创建使用哪个功能号?创建时如何设置文件属性?
答:文件创建使用功能号3CH(Create File)。文件属性通过AL寄存器设置:
- AL=00H:普通文件
- AL=01H:只读文件
- AL=02H:隐含文件
- AL=04H:系统文件
- AL=07H:隐藏+系统+只读文件
-
文件打开函数3DH的AL参数有什么含义?
答:文件打开函数3DH的AL参数指定访问模式:
- AL=00H:只读模式
- AL=01H:只写模式
- AL=02H:读写模式
- AL=10H:打开时共享模式
-
如何判断文件操作是否成功?
答:文件操作是否成功通过CF标志位和AX寄存器联合判断:
- 如果CF=0且AX不是错误码,表示操作成功
- 如果CF=1,AX中包含错误码(02H=文件未找到,05H=访问被拒绝,11H=文件名已存在等)
二、加强性实验
2.1 实验目的
掌握DOS文件功能的综合应用,实现文件复制和重命名功能。
2.2 实验内容
程序 1:文件复制程序
使用文件读写功能实现文件复制。
; 实验八-5: 文件复制程序
; 功能: 使用DOS功能号实现文件复制
DATAS SEGMENT
SRC_FILE DB 'source.txt', 0
DST_FILE DB 'dest.txt', 0
HANDLE DW ?
BUFFER DB 512 DUP(?)
ERR_OPEN DB 'Cannot open source file!', 0DH, 0AH, '$'
ERR_READ DB 'Read error!', 0DH, 0AH, '$'
ERR_WRITE DB 'Write error!', 0DH, 0AH, '$'
OK_MSG DB 'File copied successfully!', 0DH, 0AH, '$'
DATAS ENDS
STACKS SEGMENT
DB 64 DUP(?)
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES, DS:DATAS, SS:STACKS
START:
MOV AX, DATAS
MOV DS, AX
; 打开源文件
LEA DX, SRC_FILE
MOV AH, 3DH
MOV AL, 00H
INT 21H
JNC OPEN_OK
LEA DX, ERR_OPEN
MOV AH, 09H
INT 21H
JMP PROGRAM_END
OPEN_OK:
MOV HANDLE, AX
; 创建目标文件
LEA DX, DST_FILE
MOV AH, 3CH
MOV AL, 00H
INT 21H
MOV BX, AX
JNC CREATE_OK
MOV AH, 3EH
MOV BX, HANDLE
INT 21H
LEA DX, ERR_OPEN
MOV AH, 09H
INT 21H
JMP PROGRAM_END
CREATE_OK:
COPY_LOOP:
; 读取源文件
MOV CX, 512
LEA DX, BUFFER
MOV AH, 3FH
INT 21H
JNC READ_OK
MOV AH, 3EH
MOV BX, HANDLE
INT 21H
MOV AH, 3EH
INT 21H
LEA DX, ERR_READ
MOV AH, 09H
INT 21H
JMP PROGRAM_END
READ_OK:
CMP AX, 0
JE COPY_COMPLETE
; 写入目标文件
MOV CX, AX
MOV AH, 40H
INT 21H
JNC WRITE_OK
MOV AH, 3EH
MOV BX, HANDLE
INT 21H
MOV AH, 3EH
INT 21H
LEA DX, ERR_WRITE
MOV AH, 09H
INT 21H
JMP PROGRAM_END
WRITE_OK:
JMP COPY_LOOP
COPY_COMPLETE:
MOV AH, 3EH
MOV BX, HANDLE
INT 21H
MOV AH, 3EH
INT 21H
LEA DX, OK_MSG
MOV AH, 09H
INT 21H
PROGRAM_END:
MOV AH, 4CH
INT 21H
CODES ENDS
END START
程序 2:文件重命名程序
使用功能号56H重命名文件。
; 实验八-6: 文件重命名程序
; 功能: 使用DOS功能号56H重命名文件
DATAS SEGMENT
OLD_NAME DB 'oldname.txt', 0
NEW_NAME DB 'newname.txt', 0
ERR_MSG DB 'Rename error!', 0DH, 0AH, '$'
OK_MSG DB 'File renamed successfully!', 0DH, 0AH, '$'
EXIST_MSG DB 'Target file already exists!', 0DH, 0AH, '$'
DATAS ENDS
STACKS SEGMENT
DB 64 DUP(?)
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES, DS:DATAS, SS:STACKS
START:
MOV AX, DATAS
MOV DS, AX
; 重命名文件 (功能号56H)
; AH=56H, DS:DX=原文件名, ES:DI=新文件名
LEA DX, OLD_NAME
LEA DI, NEW_NAME
MOV AH, 56H
INT 21H
JNC RENAME_SUCCESS
CMP AX, 11H
JE FILE_EXISTS
LEA DX, ERR_MSG
MOV AH, 09H
INT 21H
JMP PROGRAM_END
FILE_EXISTS:
LEA DX, EXIST_MSG
MOV AH, 09H
INT 21H
JMP PROGRAM_END
RENAME_SUCCESS:
LEA DX, OK_MSG
MOV AH, 09H
INT 21H
PROGRAM_END:
MOV AH, 4CH
INT 21H
CODES ENDS
END START
2.3 实验结果
程序运行后,文件复制程序使用512字节缓冲区循环读取源文件并写入目标文件,直到遇到EOF(AX=0)为止。文件重命名程序使用功能号56H完成文件重命名操作。
2.4 思考题
-
文件复制程序中为什么要使用循环读取?
答:源文件可能很大,一次读取全部内容会占用大量内存。使用循环读取,每次只读取512字节,可以处理任意大小的文件,提高内存利用率。
-
功能号56H除了重命名外还有什么用途?
答:功能号56H(Rename/Move File)主要用于文件重命名和移动文件到不同目录。它可以将文件从一个目录移动到另一个目录,只要目标路径不同即可。
附录:DOS文件操作功能号速查表
| 功能号 | 名称 | 主要寄存器 |
|---|---|---|
| 3CH | 创建文件 | DS:DX=文件名, AL=属性, 返回:AX=句柄 |
| 3DH | 打开文件 | DS:DX=文件名, AL=访问模式, 返回:AX=句柄 |
| 3EH | 关闭文件 | BX=句柄 |
| 3FH | 读文件 | BX=句柄, CX=字节数, DS:DX=缓冲区, 返回:AX=实际读入字节数 |
| 40H | 写文件 | BX=句柄, CX=字节数, DS:DX=缓冲区, 返回:AX=实际写入字节数 |
| 41H | 删除文件 | DS:DX=文件名, AL=00H |
| 56H | 重命名文件 | DS:DX=原文件名, ES:DI=新文件名 |