File 如何使用MIPS汇编语言逐行读取文件

File 如何使用MIPS汇编语言逐行读取文件,file,io,mips,File,Io,Mips,我在为我的班级做一个项目,要求我逐行阅读文件。我们的最终目标是使用MIPS语言制作一个MIPS汇编程序,但与本文相关的问题是我无法逐行读取文件。到目前为止,我已经创建了一个从文件中读取信息的机制 .data file_loc: .asciiz "test.asm" #note: when launching from commandline, test.asm should be within the same folder as Mars.jar buffer: .space 1024 #bu

我在为我的班级做一个项目,要求我逐行阅读文件。我们的最终目标是使用MIPS语言制作一个MIPS汇编程序,但与本文相关的问题是我无法逐行读取文件。到目前为止,我已经创建了一个从文件中读取信息的机制

.data
file_loc: .asciiz "test.asm" #note: when launching from commandline, test.asm should be within the same folder as Mars.jar
buffer: .space 1024 #buffer of 1024
new_line: .asciiz "\n"  #where would I actually use this?

#error strings
readErrorMsg: .asciiz "\nError in reading file\n"
openErrorMsg: .asciiz "\nError in opening file\n"

.text
main:
jal openFile
j endProgram

openFile:
#Open file for for reading purposes
li $v0, 13          #syscall 13 - open file
la $a0, file_loc        #passing in file name
li $a1, 0               #set to read mode
li $a2, 0               #mode is ignored
syscall
bltz $v0, openError     #if $v0 is less than 0, there is an error found
move $s0, $v0           #else save the file descriptor

#Read input from file
li $v0, 14          #syscall 14 - read filea
move $a0, $s0           #sets $a0 to file descriptor
la $a1, buffer          #stores read info into buffer
li $a2, 1024            #hardcoded size of buffer
syscall             
bltz $v0, readError     #if error it will go to read error

li $v0, 4
la $a0, buffer
syscall

#Close the file 
li   $v0, 16       # system call for close file
move $a0, $s0      # file descriptor to close
syscall            # close file
jr $ra

openError:
la $a0, openErrorMsg
li $v0, 4
syscall
j endProgram

readError:
la $a0, readErrorMsg
li $v0, 4
syscall
j endProgram


endProgram:
li $v0, 10
syscall
问题是,在文件中读取将读取缓冲区(1024)中可容纳的字节数,而不是行数

例如,在名为test.asm的文件中读取以下数据:

test abc abc abc

test2 1231 123 123
将产生以下输出:

test abc abc abc

test2 1231 123 123
我希望每次只读一行:

test abc abc abc
我知道减小缓冲区大小将有助于限制此信息,但在输入行较长的情况下,可能会导致一些问题。我希望知道是否有人知道如何从缓冲区读取一定数量的数据,然后在新行指示器处拆分它(我很确定它的“\n”)


如有任何帮助/提示,将不胜感激!谢谢

当然可以像你现在这样读大块的内容。这在最小化系统调用方面是有效的,但是代码编写起来有点繁琐。您需要一个循环遍历每个块来定位任何换行符,并需要一个缓冲区来存储需要多次读取才能生成的不完整行

一种更容易编码的惰性方法是逐字节读取文件,这使得新行检测变得轻松:

# if current byte is a newline, consume line
lb $s4 ($s1)  # load the current byte from the buffer
li $t0 10     # ASCII newline
beq $s4 $t0 consume_line
您可以使用
sbrk
(系统调用9)为缓冲区分配更多内存以处理任意长的行,但在本例中,我假设行的长度永远不会超过1024字节。为了使示例最小化,我将更好的错误处理、行消耗代码和模块化留作练习

您可以将其另存为
read_file_lines.s
,使用
spim-f read_file_lines.s
运行,它将打印自己的源代码

.data  
fin: .asciiz "read_file_lines.s"
buffer: .space 1
line: .space 1024
.globl main
.text
main:
    la $s1 buffer
    la $s2 line
    li $s3 0      # current line length

    # open file
    li $v0 13     # syscall for open file
    la $a0 fin    # input file name
    li $a1 0      # read flag
    li $a2 0      # ignore mode 
    syscall       # open file 
    move $s0 $v0  # save the file descriptor 

read_loop:

    # read byte from file
    li $v0 14     # syscall for read file
    move $a0 $s0  # file descriptor 
    move $a1 $s1  # address of dest buffer
    li $a2 1      # buffer length
    syscall       # read byte from file

    # keep reading until bytes read <= 0
    blez $v0 read_done

    # naively handle exceeding line size by exiting
    slti $t0 $s3 1024
    beqz $t0 read_done

    # if current byte is a newline, consume line
    lb $s4 ($s1)
    li $t0 10
    beq $s4 $t0 consume_line

    # otherwise, append byte to line
    add $s5 $s3 $s2
    sb $s4 ($s5)

    # increment line length
    addi $s3 $s3 1

    b read_loop

consume_line:

    # null terminate line
    add $s5 $s3 $s2
    sb $zero ($s5)

    # reset bytes read
    li $s3 0

    # print line (or consume it some other way)
    move $a0 $s2
    li $v0 4
    syscall

    # print newline
    li $a0 10
    li $v0 11
    syscall

    b read_loop

read_done:

    # close file
    li $v0 16     # syscall for close file
    move $a0 $s0  # file descriptor to close
    syscall       # close file

    # exit the program
    li $v0 10
    syscall
.data
fin:.asciiz“读取文件行.s”
缓冲区:。空间1
行:。空格1024
格洛博梅因酒店
.文本
主要内容:
la$s1缓冲区
la$s2线路
li$s3 0#当前线路长度
#打开文件
li$v0 13#打开文件的系统调用
la$a0 fin#输入文件名
li$a1 0#读取标志
li$a2 0#忽略模式
系统调用#打开文件
移动$s0$v0#保存文件描述符
读循环:
#从文件中读取字节
li$v0 14#读取文件的系统调用
移动$a0$s0#文件描述符
移动$a1$s1#目的地缓冲区地址
li$a2 1#缓冲区长度
syscall#从文件中读取字节

#继续读取,直到字节读取为止,这样一次读取1024(或任何数字)字节,然后编写一个函数,返回缓冲区中的下一行。这方面有什么进展吗?