554 lines
11 KiB
Markdown
554 lines
11 KiB
Markdown
# 实验八:文件操作
|
||
|
||
## 一、基础性实验
|
||
|
||
### 1.1 实验目的
|
||
|
||
掌握DOS功能调用进行文件操作的方法,包括文件的创建、写入、读取和删除。
|
||
|
||
### 1.2 实验内容
|
||
|
||
#### 程序 1:文件创建程序
|
||
|
||
使用功能号3CH创建新文件。
|
||
|
||
```asm
|
||
; 实验八-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向文件写入数据。
|
||
|
||
```asm
|
||
; 实验八-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读取文件内容。
|
||
|
||
```asm
|
||
; 实验八-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删除文件。
|
||
|
||
```asm
|
||
; 实验八-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 思考题
|
||
|
||
1. DOS功能调用中,文件创建使用哪个功能号?创建时如何设置文件属性?
|
||
|
||
答:文件创建使用功能号3CH(Create File)。文件属性通过AL寄存器设置:
|
||
- AL=00H:普通文件
|
||
- AL=01H:只读文件
|
||
- AL=02H:隐含文件
|
||
- AL=04H:系统文件
|
||
- AL=07H:隐藏+系统+只读文件
|
||
|
||
2. 文件打开函数3DH的AL参数有什么含义?
|
||
|
||
答:文件打开函数3DH的AL参数指定访问模式:
|
||
- AL=00H:只读模式
|
||
- AL=01H:只写模式
|
||
- AL=02H:读写模式
|
||
- AL=10H:打开时共享模式
|
||
|
||
3. 如何判断文件操作是否成功?
|
||
|
||
答:文件操作是否成功通过CF标志位和AX寄存器联合判断:
|
||
- 如果CF=0且AX不是错误码,表示操作成功
|
||
- 如果CF=1,AX中包含错误码(02H=文件未找到,05H=访问被拒绝,11H=文件名已存在等)
|
||
|
||
---
|
||
|
||
## 二、加强性实验
|
||
|
||
### 2.1 实验目的
|
||
|
||
掌握DOS文件功能的综合应用,实现文件复制和重命名功能。
|
||
|
||
### 2.2 实验内容
|
||
|
||
#### 程序 1:文件复制程序
|
||
|
||
使用文件读写功能实现文件复制。
|
||
|
||
```asm
|
||
; 实验八-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重命名文件。
|
||
|
||
```asm
|
||
; 实验八-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 思考题
|
||
|
||
1. 文件复制程序中为什么要使用循环读取?
|
||
|
||
答:源文件可能很大,一次读取全部内容会占用大量内存。使用循环读取,每次只读取512字节,可以处理任意大小的文件,提高内存利用率。
|
||
|
||
2. 功能号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=新文件名 | |