Skip to content

汇编语言 - 文件管理

文件管理是程序与外部存储交互的基础。

通过系统调用,汇编程序可以打开、读取、写入和关闭文件,与高级语言一样灵活地处理文件 IO。


文件操作流程总览

文件操作遵循打开→读写→关闭的基本流程,以及三个标准文件描述符:

文件操作流程图


文件操作相关的系统调用

系统调用调用号用途主要参数
sys_open5打开/创建文件EBX=文件名, ECX=标志, EDX=权限
sys_read3读取文件EBX=fd, ECX=缓冲区, EDX=字节数
sys_write4写入文件EBX=fd, ECX=缓冲区, EDX=字节数
sys_close6关闭文件EBX=fd
sys_creat8创建文件(旧方式)EBX=文件名, ECX=权限
sys_lseek19移动文件指针EBX=fd, ECX=偏移, EDX=起始位置
sys_unlink10删除文件EBX=文件名

文件打开标志

常量说明
O_RDONLY0只读
O_WRONLY1只写
O_RDWR2读写
O_CREAT64(0x40)若文件不存在则创建
O_TRUNC512(0x200)打开时清空文件内容
O_APPEND1024(0x400)追加到文件末尾

多个标志用 OR 组合,例如 O_WRONLY | O_CREAT | O_TRUNC = 1 | 64 | 512 = 577


创建并写入文件

实例

asm
; 文件路径:file_write.asm  

; 创建文件并写入内容  

section .data  

    filename db 'runoob_output.txt', 0    ; 文件名(null 结尾)  

    content db 'Hello, RUNOOB!', 0xA       ; 要写入的内容  

    content_len equ $ - content  

    create_msg db 'File created successfully!', 0xA  

    create_msg_len equ $ - create_msg  

section .bss  

    fd resd 1                               ; 文件描述符  

section .text  

    global _start  

_start:  

    ; 1. 创建文件  

    mov eax, 8                  ; sys_creat  

    mov ebx, filename           ; 文件名  

    mov ecx, 0o644              ; 权限:rw-r--r--  

    ; 0o644 = 所有者读写、组只读、其他只读  

    int 0x80  

    mov [fd], eax               ; 保存文件描述符  

    ; 2. 写入内容到文件  

    mov eax, 4                  ; sys_write  

    mov ebx, [fd]               ; 文件描述符  

    mov ecx, content            ; 数据地址  

    mov edx, content_len        ; 数据长度  

    int 0x80  

    ; 3. 关闭文件  

    mov eax, 6                  ; sys_close  

    mov ebx, [fd]               ; 文件描述符  

    int 0x80  

    ; 4. 提示成功  

    mov eax, 4  

    mov ebx, 1  

    mov ecx, create_msg  

    mov edx, create_msg_len  

    int 0x80  

    mov eax, 1  

    mov ebx, 0  

    int 0x80

运行结果:

$ nasm -f elf32 file_write.asm -o file_write.o
$ ld -m elf_i386 file_write.o -o file_write
$ ./file_write
File created successfully!
$ cat runoob_output.txt
Hello, RUNOOB!

读取文件内容

实例

asm
; 文件路径:file_read.asm  

; 打开并读取文件内容  

section .data  

    filename db 'runoob_output.txt', 0  

    open_error db 'Error: cannot open file', 0xA  

    open_error_len equ $ - open_error  

    read_success db 'File content:', 0xA  

    read_success_len equ $ - read_success  

section .bss  

    fd resd 1  

    buffer resb 1024                 ; 读取缓冲区  

section .text  

    global _start  

_start:  

    ; 1. 打开文件(只读)  

    mov eax, 5                  ; sys_open  

    mov ebx, filename           ; 文件名  

    mov ecx, 0                  ; 只读模式  

    mov edx, 0                  ; 权限(只读时忽略)  

    int 0x80  

    cmp eax, 0                  ; 文件描述符 < 0 表示错误  

    jl  open_failed  

    mov [fd], eax               ; 保存文件描述符  

    ; 2. 读取文件内容  

    mov eax, 3                  ; sys_read  

    mov ebx, [fd]               ; 文件描述符  

    mov ecx, buffer             ; 缓冲区  

    mov edx, 1024               ; 最多读取 1024 字节  

    int 0x80  

    ; 返回值 eax = 实际读取的字节数  

    mov esi, eax                ; 保存读取字节数  

    ; 3. 关闭文件  

    mov eax, 6                  ; sys_close  

    mov ebx, [fd]  

    int 0x80  

    ; 4. 输出提示信息  

    mov eax, 4  

    mov ebx, 1  

    mov ecx, read_success  

    mov edx, read_success_len  

    int 0x80  

    ; 5. 输出文件内容到屏幕  

    mov eax, 4  

    mov ebx, 1  

    mov ecx, buffer  

    mov edx, esi                ; 使用实际读取的字节数  

    int 0x80  

    jmp exit  

open_failed:  

    mov eax, 4  

    mov ebx, 1  

    mov ecx, open_error  

    mov edx, open_error_len  

    int 0x80  

exit:  

    mov eax, 1  

    mov ebx, 0  

    int 0x80

运行结果:

$ nasm -f elf32 file_read.asm -o file_read.o
$ ld -m elf_i386 file_read.o -o file_read
$ ./file_read
File content:
Hello, RUNOOB!

追加写入文件

实例

asm
; 文件路径:file_append.asm  

; 以追加模式打开文件并写入  

section .data  

    filename db 'runoob_log.txt', 0  

    log_entry db '[INFO] Program executed successfully.', 0xA  

    log_len equ $ - log_entry  

section .bss  

    fd resd 1  

section .text  

    global _start  

_start:  

    ; 打开文件(创建 + 追加模式)  

    mov eax, 5                  ; sys_open  

    mov ebx, filename           ; 文件名  

    mov ecx, 0x441              ; O_WRONLY | O_CREAT | O_APPEND  

    ; O_WRONLY=1, O_CREAT=0x40, O_APPEND=0x400  

    ; 组合:1 | 0x40 | 0x400 = 0x441  

    mov edx, 0o644              ; 创建时的权限  

    int 0x80  

    mov [fd], eax  

    ; 追加写入  

    mov eax, 4                  ; sys_write  

    mov ebx, [fd]               ; 文件描述符  

    mov ecx, log_entry          ; 日志内容  

    mov edx, log_len  

    int 0x80  

    ; 关闭文件  

    mov eax, 6  

    mov ebx, [fd]  

    int 0x80  

    mov eax, 1  

    mov ebx, 0  

    int 0x80

复制文件

一个综合示例:将一个文件的内容复制到另一个文件:

实例

asm
; 文件路径:file_copy.asm  

; 复制文件:将 runoob_input.txt 复制到 runoob_copy.txt  

section .data  

    src_file db 'runoob_input.txt', 0  

    dst_file db 'runoob_copy.txt', 0  

    success_msg db 'File copied successfully!', 0xA  

    success_len equ $ - success_msg  

    error_msg db 'Error during file copy', 0xA  

    error_len equ $ - error_msg  

section .bss  

    src_fd resd 1  

    dst_fd resd 1  

    buffer resb 4096              ; 4KB 复制缓冲区  

section .text  

    global _start  

_start:  

    ; 1. 打开源文件(只读)  

    mov eax, 5  

    mov ebx, src_file  

    mov ecx, 0                   ; O_RDONLY  

    mov edx, 0  

    int 0x80  

    cmp eax, 0  

    jl  error_exit  

    mov [src_fd], eax  

    ; 2. 创建目标文件  

    mov eax, 8                   ; sys_creat  

    mov ebx, dst_file  

    mov ecx, 0o644  

    int 0x80  

    cmp eax, 0  

    jl  error_exit  

    mov [dst_fd], eax  

copy_loop:  

    ; 3. 从源文件读取  

    mov eax, 3                   ; sys_read  

    mov ebx, [src_fd]  

    mov ecx, buffer  

    mov edx, 4096  

    int 0x80  

    ; eax = 实际读取的字节数  

    cmp eax, 0                   ; 读到 0 字节?  

    jle copy_done                ; 是,文件结束  

    ; 4. 写入目标文件  

    mov esi, eax                 ; 保存读取的字节数  

    mov eax, 4                   ; sys_write  

    mov ebx, [dst_fd]  

    mov ecx, buffer  

    mov edx, esi                 ; 写入实际读取的字节数  

    int 0x80  

    jmp copy_loop                ; 继续循环  

copy_done:  

    ; 5. 关闭文件  

    mov eax, 6                   ; sys_close  

    mov ebx, [src_fd]  

    int 0x80  

    mov eax, 6  

    mov ebx, [dst_fd]  

    int 0x80  

    ; 6. 输出成功信息  

    mov eax, 4  

    mov ebx, 1  

    mov ecx, success_msg  

    mov edx, success_len  

    int 0x80  

    jmp exit  

error_exit:  

    mov eax, 4  

    mov ebx, 1  

    mov ecx, error_msg  

    mov edx, error_len  

    int 0x80  

exit:  

    mov eax, 1  

    mov ebx, 0  

    int 0x80

文件操作前后务必检查系统调用的返回值(在 EAX 中)。负值表示错误(如 -2 是 ENOENT 文件不存在,-13 是 EACCES 权限不足),忽略错误返回值是文件操作 bug 的最大来源。