You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

32位汇编实现文件行序反转:写入目标文件遇阻求指导

解决汇编中用fseek反转文件行并写入的问题

嘿,第一次用汇编处理文件行反转确实有点绕,尤其是fseek的用法容易踩坑。你老师提示用fseek完全正确,核心思路就是从源文件末尾倒着找每行的结束标记,再把该行内容写到目标文件里。我帮你拆解下流程,再给个带注释的汇编代码示例,应该能解决你写不进file2的问题。

首先理清楚核心逻辑:

  • 必须确保源文件(file1)和目标文件(file2)正确打开——很多新手写不进文件都是因为file2的打开模式错了,比如用了只读模式,或者路径不对。
  • 用fseek定位到file1末尾,从后往前逐个字节检查,找到换行符\n(这是上一行的结束标记)。
  • 找到换行符后,定位到该行开头,读取整行内容写入file2。
  • 重复上述过程直到文件开头,最后处理没有前置换行符的第一行。

汇编中使用fseek的关键注意事项

fseek是C标准库函数,stdcall调用约定下参数要从右往左压栈,原型为fseek(FILE* stream, long offset, int origin),对应汇编调用顺序:
invoke fseek, 文件指针, 偏移量, 起始位置
其中起始位置的常用宏值:

  • SEEK_SET(值0):从文件开头偏移
  • SEEK_CUR(值1):从当前指针位置偏移
  • SEEK_END(值2):从文件末尾偏移

你之前可能踩坑的点:偏移量正负搞反(倒找要用负数)、起始位置选错,或者调用fseek后没正确更新指针位置。

完整汇编代码示例(带详细注释)

.386
.model flat, stdcall
option casemap :none

; 引入C标准库
includelib msvcrt.lib
fopen      proto c :ptr byte, :ptr byte
fseek      proto c :ptr, :sdword, :sdword
ftell      proto c :ptr
fread      proto c :ptr, :dword, :dword, :ptr
fwrite     proto c :ptr, :dword, :dword, :ptr
fclose     proto c :ptr
printf     proto c :ptr byte, :vararg

.data
; 文件名
file1_name db "file1.txt", 0
file2_name db "file2.txt", 0
; 文件打开模式
mode_read  db "r", 0
mode_write db "w", 0
; 错误提示信息
err_open   db "Failed to open file!", 0ah, 0
; 行内容缓冲区(可根据需求调整大小)
buffer     db 1024 dup(0)

.data?
file1      dd ?          ; 源文件指针
file2      dd ?          ; 目标文件指针
file_size  sdword ?      ; 源文件总大小
current_pos sdword ?     ; 当前倒查的位置
bytes_read dword ?       ; 读取的字节数

.code
start:
    ; 打开源文件(只读模式)
    invoke fopen, addr file1_name, addr mode_read
    mov file1, eax
    cmp eax, 0
    je open_error

    ; 打开目标文件(写入模式,不存在则创建,存在则清空)
    invoke fopen, addr file2_name, addr mode_write
    mov file2, eax
    cmp eax, 0
    je open_error

    ; 定位到源文件末尾,获取文件总大小
    invoke fseek, file1, 0, 2   ; SEEK_END = 2
    invoke ftell, file1
    mov file_size, eax
    mov current_pos, eax

reverse_loop:
    ; 从当前位置倒移1字节
    invoke fseek, file1, -1, 1  ; SEEK_CUR = 1
    dec current_pos
    cmp current_pos, 0
    jl process_first_line       ; 到文件开头,处理第一行

    ; 读取当前字节,判断是否为换行符\n
    invoke fread, addr buffer, 1, 1, file1
    cmp buffer, 0ah             ; 0ah是ASCII的换行符
    jne reverse_loop            ; 不是换行符,继续倒查

    ; 找到换行符,定位到该行起始位置(换行符+1)
    invoke fseek, file1, 1, 1
    ; 计算该行长度:当前位置+1 - 行起始位置
    mov eax, current_pos
    add eax, 1
    sub eax, [esp+4]            ; esp+4是fseek返回的行起始位置
    mov bytes_read, eax

    ; 读取整行内容到缓冲区,写入目标文件
    invoke fread, addr buffer, 1, bytes_read, file1
    invoke fwrite, addr buffer, 1, bytes_read, file2

    ; 更新当前位置为换行符位置,继续倒查
    mov eax, [esp+4]
    dec eax
    mov current_pos, eax
    invoke fseek, file1, current_pos, 0  ; SEEK_SET =0
    jmp reverse_loop

process_first_line:
    ; 处理第一行:从文件开头到剩余位置的内容
    mov eax, file_size
    sub eax, current_pos
    mov bytes_read, eax
    invoke fseek, file1, 0, 0   ; 定位到文件开头
    invoke fread, addr buffer, 1, bytes_read, file1
    invoke fwrite, addr buffer, 1, bytes_read, file2

    ; 关闭文件(必须执行,否则缓冲区内容可能未写入磁盘)
    invoke fclose, file1
    invoke fclose, file2
    jmp exit_program

open_error:
    invoke printf, addr err_open
    ; 若已打开文件,需关闭释放资源
    cmp file1, 0
    jne close_file1
    cmp file2, 0
    jne close_file2
    jmp exit_program

close_file1:
    invoke fclose, file1
close_file2:
    invoke fclose, file2

exit_program:
    ret
end start

排查写入失败的小提示

  • 检查file2的打开模式是否为"w":如果写成"r"等只读模式,肯定写不进内容。
  • 写完后一定要调用fclose:C库会把缓冲区内容刷新到磁盘,否则可能看起来没写入。
  • 确认缓冲区大小:如果源文件的行长度超过缓冲区,会导致内容截断或写入异常。
  • 检查文件路径:如果file1不在当前目录,要写全路径,否则会打开失败。

内容的提问来源于stack exchange,提问作者Foxy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:45:47