如何使用16位DOS调用从文件中读取字符并统计总数
x86 DOS汇编实现TXT文件字符计数问题解决方案
现有代码的核心问题
- 功能号误用:打开文件的DOS中断功能号是
3Dh,你代码里写成了读文件的3Fh,根本没完成文件打开操作 - 文件名格式错误:
int 21h 0Ah输入的字符串是带长度前缀的格式,且DOS打开文件要求传入*ASCIIZ结尾(末尾加0)*的文件名,你直接传输入缓冲区首地址是无效的 - 未存储文件句柄:打开文件成功后返回的句柄存在AX中,你没有写入
handle变量,后续读取操作的BX参数是无效值 - 读取逻辑缺失:没有循环读取、计数的逻辑,只单次读4个字节肯定无法统计全文件字符数
正确实现步骤
- 处理用户输入的文件名:把
0Ah输入的文件名末尾补0,转为ASCIIZ格式 - 调用
int 21h 3Dh打开文件,保存返回的文件句柄 - 循环读取文件内容:
- 每次调用
int 21h 3Fh读取内容,可选择单次读1个字节(适合初学者理解)或者批量读缓冲区大小的字节(效率更高) - 把实际读到的字节数累加到总计数变量中
- 当读到的字节数为0时,代表已到文件末尾,退出循环
- 每次调用
- (可选)输出总计数,关闭文件(
int 21h 3Eh)后退出程序
修正后的可运行代码
.data fname_input db 255,?,255 dup(0) ; 最后预留0位置,方便转ASCIIZ buff db 256 dup(0) ; 读缓冲区 endl db 13,10,"$" handle dw ? count dw 0 ; 存储总字符数 num_buf db 6 dup(0) ; 用来转数字输出的缓冲区 .code start: mov dx, @data mov ds, dx ; 1. 读取用户输入的文件名 mov ah, 0Ah mov dx, offset fname_input int 21h ; 处理文件名:末尾加0转ASCIIZ xor bx, bx mov bl, fname_input[1] ; 取实际输入的文件名长度 mov fname_input[2+bx], 0 ; 文件名从偏移2开始,末尾补0 ; 2. 打开文件 mov ah, 3Dh mov al, 00 ; 只读模式 mov dx, offset fname_input + 2 ; 指向实际ASCIIZ文件名起始位置 int 21h jc exit ; 打开失败直接退出 mov [handle], ax ; 保存文件句柄 read_loop: ; 3. 循环读文件,每次读255字节 mov ah, 3Fh mov bx, [handle] mov cx, 255 mov dx, offset buff int 21h jc close_file ; 读出错就关闭文件退出 cmp ax, 0 je read_finish ; 读到0字节,文件读完了 add [count], ax ; 把本次读到的字节数加到总计数 ; 如果你要逐个处理字符,这里可以加循环遍历buff里的ax个字符,按需编辑 jmp read_loop read_finish: ; 这里可以加把count转成字符串输出的代码,验证计数结果 close_file: ; 关闭文件 mov ah, 3Eh mov bx, [handle] int 21h exit: mov ax, 4c00h int 21h end start
逐个字符读取的实现说明
如果你要逐个读取字符理解逻辑,把读取部分改成如下逻辑即可:
read_loop: mov ah, 3Fh mov bx, [handle] mov cx, 1 ; 每次只读1个字节 mov dx, offset buff int 21h jc close_file cmp ax, 0 je read_finish inc [count] ; 计数+1 ; 这里直接取buff[0]就是当前读到的字符,可直接编辑处理 jmp read_loop
内容的提问来源于stack exchange,提问作者NewAtC
相关产品推荐
相关产品推荐

