文件I/O基础

一个通用的 IO 模型通常包括打开文件、读写文件、关闭文件这些基本操作, 主要涉及到 4 个函数: open()、 read()、 write()以及 close()
 

一、文件描述符

调用 open 函数会有一个返回值,返回int 类型的数据。在 open函数执行成功的情况下, 会返回一个非负整数, 该返回值为一个文件描述符(file descriptor) , 这说明文件描述符是一个非负整数; 对于 Linux 内核而言,所有打开的文件都会通过文件描述符进行索引。

当调用 open 函数打开一个现有文件或创建一个新文件时,内核会向进程返回一个文件描述符, 用于指代被打开的文件,所有执行 IO 操作的系统调用都是通过文件描述符来索引到对应的文件

对于一个进程来说,文件描述符是一种有限资源, 文件描述符是从 0 开始分配的,譬如说进程中第一个被打开的文件对应的文件描述符是 0、第二个文件是 1、第三个文件是 2、第 4 个文件是 3……以此类推,文件描述符数字最大值为 1023(0~1023)。每一个被打开的文件在同一个进程中都有一个唯一的文件描述符,不会重复,如果文件被关闭后,它对应的文件描述符将会被释放,那么这个文件描述符将可以再次分配给其它打开的文件、与对应的文件绑定起来。

但是,当我们在程序中,调用 open 函数打开文件的时候,分配的文件描述符一般都是从 3 开始,因为0、 1、 2 这三个文件描述符已经默认被系统占用,分别分配给系统标准输入(0)、 标准输出(1)以及标准错误(2)

注:Linux 系统下,一切皆文件,也包括各种硬件设备,使用 open 函数打开任何文件成功情况下便会返回对应的文件描述符 fd。每一个硬件设备都会对应于 Linux 系统下的某一个文件,把这类文件称为设备文件。所以设备文件对应的是某一硬件设备,应用程序通过对设备文件进行读写等操作、来使用、操控硬件设备,如 LCD 显示器、串口、音频。

标准输入是键盘,0 :打开键盘对应的设备文件时所得到的文件描述符;标准输出是 LCD 显器,1 :打开 LCD 设备对应的设备文件时所得到的文件描述符;而标准错误: LCD 显示器。

二、open()

在 Linux 系统中要操作一个文件,需要先打开该文件,得到文件描述符,然后再对文件进行相应的读写操作,最后在关闭该文件; open 函数用于打开文件,并且也可以创建一个新的文件。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

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

pathname:用于标识需要打开或创建的文件,可以包含路径信息。
flags:调用 open 函数时需要提供的标志, 包括文件访问模式标志以及其它文件相关标志

mode:只有使用 O_CREAT 或 O_TMPFILE 标志时才有效,用于指定新文件的访问权限  

标志 用途 说明
O_RDONLY 以只读方式打开文件
O_WRONLY 以只写方式打开文件
O_RDWR 以可读可写的方式打开文件

前三个是文件访问权限标志,

必须包含其中一种,并且只能是一种

O_CREAT 文件不存在,则创建此文件 需要传入第3个参数mode,用于指定新文件的访问权限  
O_DIRECTORY pathname不为目录,则调用失败
O_EXCL 用于创建文件
O_NOFOLLOW pathname指向符号连接,将不对其解引用,返回错误

注:除了前三种标志,可以通过位或运算(|)将多个标志进行组合
 

mode 参数的类型是 mode_t,为u32 无符号整形数据,权限表示方法如下所示:

O---其他用户的权限
G---同组用户(group)的权限,即与文件所有者有相同组 ID 的所有用户
U---文件所属用户的权限,即文件或目录的所属者
S---文件的特殊权限,文件特殊权限一般用的比较少

3 个 bit 位中,按照 rwx 顺序来分配权限位(特殊权限除外) 。最高位(权值为 4)表示权限,为 1 时表示具有读权限,为 0 时没有读权限;中间位(权值为 2)表示权限,为 1 时表示具有
写权限,为 0 时没有写权限;最低位(权值为 1)表示执行权限,为 1 时表示具有可执行权限,为 0 时没有执行权限。

111000000:表示文件所属者具有读、写、执行权限,同组用户和其他用户不具有任何权限


100100100:表示文件所属者、同组用户以及其他用户都具有读权限,但没有写、执行限

文件权限宏定义:

 三、write()

调用 write 函数可向打开的文件写入数据

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

fd:将进行写操作的文件所对应的文件描述符传递给 write 函数

buf: 指定写入数据对应的缓冲区
count: 指定写入的字节数
返回值: 如果成功将返回写入的字节数(0 表示未写入任何字节)

注意:读写操作都是从文件的当前位置偏移量处开始。默认情况下当前位置偏移量一般是 0,指向了文件起始位置,当调用 read、 write 函数读写操作完成之后, 当前位置偏移量也会向后移动对应字节数。

四、read()

调用 read 函数可从打开的文件中读取数据

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);

fd: 文件描述符
buf: 指定用于存储读取数据的缓冲区

count: 指定需要读取的字节数

返回值: 如果读取成功将返回读取到的字节数

 五、close()

调用 close 函数关闭一个已经打开的文件

#include <unistd.h>
int close(int fd);

fd: 文件描述符,需要关闭的文件所对应的文件描述符
返回值: 如果成功返回 0,如果失败则返回-1

六、lseek() 

对于每个打开的文件, 系统都会记录它的读写位置偏移量,把读写位置偏移量称为读写偏移量,记录了文件当前的读写位置,当调用 read()或 write()函数对文件进行读写操作时,就会从当前读写位置偏移量开始进行数据读写。

读写偏移量用于指示 read()或 write()函数操作时文件的起始位置,会以相对于文件头部的位置偏移量来表示,文件第一个字节数据的位置偏移量为 0。

#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);

fd: 文件描述符。
offset: 偏移量,以字节为单位。
whence: 用于定义参数 offset 偏移量对应的参考值,如下:

1.SEEK_SET:读写偏移量将指向 offset 字节位置处(从文件头部开始算

2.SEEK_CUR:读写偏移量将指向当前位置偏移量 + offset 字节位置处,

3.SEEK_END:读写偏移量将指向 文件末尾 + offset 字节位置处

返回值: 成功将返回从文件头部开始算起的位置偏移量(字节为单位), 当前的读写位置
 

猜你喜欢

转载自blog.csdn.net/qq_53144843/article/details/124530364