Emu8086汇编修改文件内容并保存新文件报错问题排查
问题:DOS中断21h 3Ch功能创建文件时总是触发错误处理(路径已确认无误)
需求:实现将文件中用户从键盘输入的指定字符替换为本人名字,并保存为新文件。
问题现象:代码中write_to_new_file段调用DOS中断21h的3Ch功能创建新文件时,总是跳转至file_error错误处理分支,且已确认目标文件路径c:\emu8086\vdrive\C\created_folder\file_corrected.txt是正确的。
相关代码片段
write_to_new_file: mov ah, 3Ch lea dx, new_file mov al, 0 int 21h jc file_error mov bx, ax
完整代码
org 100h jmp start ; File paths file1 db "c:\emu8086\vdrive\C\file1.txt", 0 ; and files 2 and 3 almost same paths new_file db "c:\emu8086\vdrive\C\created_folder\file_corrected.txt", 0 handle dw ? ... ; General messages ... ; Replace functionality messages ... start: mov ax, cs ;mov dx, ax mov es, ax ... ;********** REPLACEMENT ********************* ; Create new file lea dx, new_file mov ah, 3Ch ; Create file function mov cx, 0 ; Normal attributes int 21h mov bx, ax ; Save handle of new file in BX choose_file_for_replacement: mov dx, offset replace_message ; Load address of footer mov ah, 09h ; DOS service to display string int 21h ; Call DOS interrupt ; Wait for user input mov ah, 01h ; DOS service to read character int 21h ; Call DOS interrupt ; Compare input directly with ASCII values for '1', '2', '3' cmp al, '1' ; Compare with '1' je replace_file1 cmp al, '2' ; Compare with '2' je replace_file2 cmp al, '3' ; Compare with '3' je replace_file3 replace_file1: ; Initialize data segment mov ax, @data mov ds, ax ; Open the file mov ah, 3Dh ; Open file function mov al, 0 ; Open for reading lea dx, file1 ; Load address of file name int 21h jc file_error ; If error, jump to error handling mov bx, ax ; Store file handle in BX jmp read_into_buffer replace_file2: ... replace_file3: ... read_into_buffer: mov ah, 3Fh ; Read file function lea dx, buf ; Load address of buffer mov cx, 255 ; Number of bytes to read int 21h jc file_error ; If error, jump to error handling mov si, offset buf ; SI points to the buffer ; Prompt user to enter the character to replace mov ah, 02h ; DOS service to write character mov dx, offset prompt mov ah, 9 int 21h ; Read the character from the user mov ah, 01h int 21h mov bl, al ; Store user input in BL mov ah, 02h ; DOS service to write character ; Process the buffer process_message: mov al, [si] cmp al, 0 je write_to_new_file cmp al, bl jne skip_replacement ; Replace character with name mov di, offset replacement output_replacement: mov al, [di] cmp al, 0 je continue_processing mov dl, al mov ah, 2 int 21h inc di jmp output_replacement skip_replacement: mov dl, al mov ah, 2 int 21h continue_processing: inc si jmp process_message write_to_new_file: mov ah, 3Ch lea dx, new_file mov al, 0 int 21h jc file_error mov bx, ax ; Calculate the length of the modified buffer mov cx, si ; SI points to the end of the modified part ; Write the modified content to the new file mov ah, 40h lea dx, buf int 21h jc file_error ; Close the new file mov ah, 3Eh int 21h ; Display success message lea dx, success_message mov ah, 9 int 21h jmp end_program file_error: ; Display error message lea dx, message_error mov ah, 9 int 21h jmp end_program ...
问题分析
- DS寄存器指向错误:在
replace_file1中执行了mov ax, @data和mov ds, ax,但new_file定义在CS段(COM程序默认代码、数据同属CS段),此时DS指向@data段,导致lea dx, new_file加载的路径地址错误,DOS无法定位正确路径。 - 3Ch功能参数问题:
- 未显式设置
cx寄存器(文件属性),虽默认可为0,但显式设置更规范; al=0表示仅创建新文件,若目标文件已存在则创建失败,触发CF标志跳转至错误处理。
- 未显式设置
- 重复创建文件:
start段提前调用3Ch创建new_file,后续write_to_new_file再次调用时,若文件已存在且al=0,必然触发错误。 - 缓冲区处理逻辑错误:当前代码仅将替换内容输出到屏幕,未修改
buf数据,导致写入新文件的仍是原始内容;同时缓冲区长度计算mov cx, si错误,正确长度应为si - offset buf。
解决方案
1. 修正DS寄存器指向
在write_to_new_file开头将DS重置为CS,确保正确访问CS段中的new_file路径:
write_to_new_file: mov ax, cs mov ds, ax ; 让DS指向CS,正确读取new_file路径 mov ah, 3Ch lea dx, new_file mov cx, 0 ; 显式设置文件属性为普通 mov al, 1 ; al=1表示文件存在则截断(覆盖),避免已存在时出错 int 21h jc file_error mov bx, ax
2. 移除重复的文件创建代码
删除start段中提前创建new_file的代码,避免重复创建导致的错误:
;********** REPLACEMENT ********************* ; 以下代码删除 ; Create new file ; lea dx, new_file ; mov ah, 3Ch ; Create file function ; mov cx, 0 ; Normal attributes ; int 21h ; mov bx, ax ; Save handle of new file in BX
3. 修正缓冲区长度计算
将错误的长度计算改为实际处理的字节数:
; Calculate the length of the modified buffer mov cx, si sub cx, offset buf ; 得到缓冲区中实际处理的字节数
4. 修正缓冲区修改逻辑
修改process_message段,将替换后的名字写入缓冲区,而不是仅输出到屏幕:
; Process the buffer process_message: mov al, [si] cmp al, 0 je write_to_new_file cmp al, bl jne skip_replacement ; Replace character with name: 将名字写入缓冲区 mov di, offset replacement output_replacement: mov al, [di] cmp al, 0 je continue_processing mov [si], al ; 把名字字符写入缓冲区当前位置 inc si inc di jmp output_replacement skip_replacement: ; 字符不替换,直接移动到下一个位置 inc si jmp process_message
注意:需确保
buf的大小足够容纳替换后的内容(单个字符替换为多字符名字会增加总长度),可适当增大缓冲区定义(如改为buf db 512 dup(0))。
内容的提问来源于stack exchange,提问作者anniee
相关产品推荐
相关产品推荐

