没志青年
发布于 2025-06-14 / 27 阅读
0

[1] Linux 文件 IO 编程

errno

很多函数失败返回-1 并设置 errno,errno是啥

errno = “最近一次系统调用失败的原因编号(整数)”

每个线程私有。

这个编号只有在出错的时候才会更新,平时读的都是上一次的。

查询errno:

man 3 errno
errno -l

使用方法1:只打印编号

int fd = open("test.txt", O_RDONLY);

if (fd == -1) {
printf(“errno=%d\n”, errno);
}

使用方法2:打印错误原因

printf(“%s\n”, strerror(errno));

输出:
No such file or directory

使用方法3:打印错误原因

perror(“open”);

输出:
open: No such file or directory

errno 表:

Linux errno 错误码对照表

系统调用

open

#include <fcntl.h>

int open(const char pathname, int flags, …
/
mode_t mode */ );

  • 成功:文件描述符

  • 失败:-1 并设置 errno

flags:进程打算如何访问这个文件。

以下三个访问模式,三选一,必选。

  • O_RDONLY:只读

  • O_WRONLY:只写

  • O_RDWR:读写

拓展标志选项:

标志

说明

O_CREAT

如果文件不存在,则创建文件(需要指定 mode 参数)

O_EXCL

与 O_CREAT 同用,若文件已存在,则出错(防止覆盖)

O_TRUNC

如果文件已存在,打开时将其长度截断为0(清空文件)

O_APPEND

每次写入都追加到文件末尾

O_NONBLOCK

非阻塞模式(用于设备或管道等)

O_SYNC

每次写入都等待数据写入物理设备(同步写)

O_DSYNC

类似于 O_SYNC,但只同步数据,不同步元数据

O_NOFOLLOW

不跟随符号链接

O_CLOEXEC

在执行 exec 系列系统调用时自动关闭文件描述符

mode:当打开一个不存在的文件时,指定新文件的访问权限位。

close

#include <unistd.h>

int close(int fd);

参数:

  • close:文件描述符

返回值:

  • 成功:0

  • 失败:-1 并设置 errno

read

 #include <unistd.h>

ssize_t read(int fd, void buf[.count], size_t count);

参数:

  • fd:文件描述符

  • buf:缓冲区

  • count:要读取多少字节

返回值:

  • 成功:读取到的数据的字节数,(读文件时 0 表示到达文件尾了没有可读的了)

  • 失败:-1 并设置 errno,常见错误:EAGAIN(EWOULDBLOCK)、EBADF、EFAULT、EINTR、EINVAL、EIO、EISDIR

write

#include <unistd.h>

ssize_t write(int fd, const void buf[.count], size_t count);

参数:

  • fd:文件描述符

  • buf:数据缓冲区

  • count:要写入多少字节

返回值:

  • 成功:返回成功写入的字节数

  • 失败:-1 并设置 errno

lseek

调整文件读写指针的位置。

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

参数:

  • offset:

  • whence:

    • SEEK_SET:

    • SEEK_CUR:

    • SEEK_END:

    • SEEK_DATA:

    • SEEK_HOLE:

返回值:

  • 成功:返回

  • 失败:设置 errno,返回

C语言库函数

#include <stdio.h>

FILE *fopen(const char *restrict pathname, const char *restrict mode);
FILE *fdopen(int fd, const char *mode);
FILE *freopen(const char *restrict pathname, const char *restrict mode,
FILE restrict stream);

参数:

返回值:

  • 成功:

  • 失败:-1 并设置 errno

高级知识 - Linux 文件管理原理

内核使用3个数据结构来表示打开的文件

(1)v-node 表(v-node table)

Linux将打开文件的属性信息保存在索引节点对象(inode object,又称为v-node)中。

文件属性信息包括文件名、文件大小、访问权限、修改时间等。

(2)文件表(file table)

Linux将打开文件的信息保存在文件对象(file object)中,即 file 结构。

(3)描述符表(descriptor table)

每一个进程都有一个文件描述符表。

该表为 struct file fd_array[NR_OPEN_DEFAULT],索引号即 open 函数的返回值,称为描述符 descriptor。

之后的文件操作都使用该文件描述符来定位文件对象file,进一步通过v-node对象来获取文件属性。

文件描述符

标准输入输出

文件打开过程

内核中文件I/O数据结构共享原理

参数:

返回值:

  • 成功:

  • 失败:-1 并设置 errno


参数:

返回值:

  • 成功:

  • 失败:-1 并设置 errno

参数:

返回值:

  • 成功:

  • 失败:-1 并设置 errno


参数:

返回值:

  • 成功:

  • 失败:-1 并设置 errno