# 实验八:文件操作 ## 一、基础性实验 ### 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=新文件名 |