现在位置: 首页 > 汇编语言 > 正文

汇编语言 - 文件管理

文件管理是程序与外部存储交互的基础。通过系统调用,汇编程序可以打开、读取、写入和关闭文件,与高级语言一样灵活地处理文件 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


创建并写入文件

实例

; 文件路径: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!

读取文件内容

实例

; 文件路径: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!

追加写入文件

实例

; 文件路径: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

复制文件

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

实例

; 文件路径: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 的最大来源。