MIPS逐行读取文件异常:字符重复或额外换行问题求助
MIPS汇编文件读取问题修复
问题分析
你的代码存在三个核心问题:
- 未定义文件名常量:
.data段缺少filename的字符串定义,导致文件打开操作无效,后续读取行为异常。 - 字符串无终止符:使用
syscall 4输出字符串时,会一直读取到\0终止符,但你每次读取后没有在缓冲区末尾添加终止符,导致输出时可能包含缓冲区中残留的旧数据,出现字符重复。 - 未处理换行符:文本每行是8个十六进制数字+换行符(共9字节),每次只读8字节会把换行符留在文件指针位置,导致后续读取时先读换行符,输出时出现额外换行或字符截断。
修复后的代码
.data filename: .asciiz "sample.text" # 补充文件名定义 buffer: .space 1024 .text main: # 打开文件 li $v0, 13 la $a0, filename # 修正语法(原代码缺少逗号) li $a1, 0 # 只读模式 li $a2, 0 syscall move $s0, $v0 # 保存文件描述符 readline: # 读取文件内容(每次读1字节,直到换行或EOF) li $v0, 14 move $a0, $s0 la $a1, buffer li $a2, 1 # 逐字节读取,方便处理换行 syscall beq $v0, $zero, done_input # 读取到EOF退出 # 判断是否是换行符 lb $t0, buffer beq $t0, '\n', print_line # 读到换行符,输出当前行 # 不是换行符,继续读取下一个字节 j readline print_line: # 在缓冲区末尾添加终止符(这里假设已经读了8个数字+换行,共9字节) sb $zero, buffer+9 # 输出缓冲区内容 li $v0, 4 la $a0, buffer syscall j readline done_input: # 关闭文件(原代码遗漏,好习惯) li $v0, 16 move $a0, $s0 syscall li $v0, 10 syscall
关键修复点说明
- 补充文件名定义:在
.data段添加filename: .asciiz "sample.text",确保文件能正确打开。 - 逐字节读取处理换行:改为每次读1字节,直到遇到换行符,这样能完整读取每行的8个数字+换行,避免拆分读取导致的换行混乱。
- 添加字符串终止符:在输出前给缓冲区添加
\0,确保syscall 4只输出当前行的内容,不会读取到之前的残留数据。 - 补充文件关闭操作:使用
syscall 16关闭文件,避免资源泄漏。
替代方案(固定长度读取)
如果确定每行严格是8个数字+换行(9字节),也可以直接每次读9字节,然后添加终止符输出:
readline: li $v0, 14 move $a0, $s0 la $a1, buffer li $a2, 9 # 读取整行(8数字+换行) syscall beq $v0, $zero, done_input sb $zero, buffer($v0) # 根据实际读取字节数加终止符 li $v0, 4 la $a0, buffer syscall j readline
这种方式更高效,但要注意如果文件最后一行没有换行符,需要额外处理。
内容的提问来源于stack exchange,提问作者Jakurb
相关产品推荐
相关产品推荐

