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
相关产品推荐
相关产品推荐

