文件IO基础

文件IO是指对文件的输入输出操作。

文件描述符

调用函数会有返回值,该返回值为一个文件描述符,对于Linux内核而言,所有打开文件都会通过文件描述符进行索引。

当调用open函数打开或者创建一个新文件,内核会向进程返回一个文件描述符,用于指带被打开的文件,所有执行 IO 操作的系统调用都是通过文件描述符来索引到对应的文件。一个进程可以打开多个文件,但是在 Linux 系统中,一个进程可以打开的文件数是有限制,并不是可以无限制打开很多的文件。

1
2
$ ulimit -n					##查看进程打开文件的最大数量
1024

每一个被打开的文件在同一个进程中都有一个唯一的文件描述符,不会重复,如果文件被关闭后,它对应的文件描述符将会被释放,那么这个文件描述符将可以再次分配给其它打开的文件、与对应的文件绑定起来。

每次给打开的文件分配文件描述符都是从最小的没有被使用的文件描述符(0~1023)开始,当之前打开的文件被关闭之后,那么它对应的文件描述符会被释放,释放之后也就成为了一个没有被使用的文件描述符了。

但是 0、1、2 这三个文件描述符已经默认被系统占用了,分别分配给了系统标准输入(0)、标准输出(1)以及标准错误(2)。

open打开文件

函数原型

1
2
3
4
5
#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);

open 函数用于打开文件,当然除了打开已经存在的文件之外,还可以创建一个新的文件。

在应用程序中调用 open 函数即可传入 2 个参数(pathname、flags)、也可传入 3 个参数(pathname、flags、mode),但是第三个参数 mode 需要在第二个参数 flags 满足条件时才会有效,稍后将对此进行说明;从图 2.3.1 可知,在应用程序中使用 open 函数时,需要包含 3 个头文件“#include
”、“#include ”、“#include ”。

函数参数和返回值定义

pathname:字符串类型,用于标识需要打开或创建的文件,可以包含路径(绝对路径或者相对路径)信息。

flags:调用open函数时需要提供的标志,包括文件访问模式标志以及其它文件相关标志,这些标志使用宏定义进行描述。

1
2
3
int fd = open("./app.c", O_RDWR)				//打开一个已经存在的文件,使用可读可写的方式打开
if (-1 == fd)
return fd;

write写文件

函数原型

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

函数参数返回值含义如下:

fd:文件描述符。将进行写操作的文件所对应的文件描述符传递给 write 函数。
buf:指定写入数据对应的缓冲区。
count:指定写入的字节数。
返回值:如果成功将返回写入的字节数(0 表示未写入任何字节),如果此数字小于 count 参数,这不是错误,譬如磁盘空间已满,可能会发生这种情况;如果写入出错,则返回-1。

read读文件

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

函数参数和返回值含义如下:
fd:文件描述符。与 write 函数的 fd 参数意义相同。

buf:指定用于存储读取数据的缓冲区。

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

返回值:如果读取成功将返回读取到的字节数,实际读取到的字节数可能会小于 count 参数指定的字节
数,也有可能会为 0,譬如进行读操作时,当前文件位置偏移量已经到了文件末尾。实际读取到的字节数少
于要求读取的字节数,譬如在到达文件末尾之前有 30 个字节数据,而要求读取 100 个字节,则 read 读取成
功只能返回 30;而下一次再调用 read 读,它将返回 0(文件末尾)。

close关闭文件

函数原型

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

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

lseek

函数原型

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

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

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

函数参数和返回值含义如下:
fd:文件描述符。
offset:偏移量,以字节为单位。
whence:用于定义参数 offset 偏移量对应的参考值,该参数为下列其中一种(宏定义):

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

SEEK_CUR:读写偏移量将指向当前位置偏移量 + offset 字节位置处,offset 可以为正、也可以为负,如果是正数表示往后偏移,如果是负数则表示往前偏移;

SEEK_END:读写偏移量将指向文件末尾 + offset 字节位置处,同样 offset 可以为正、也可以为负,如果是正数表示往后偏移、如果是负数则表示往前偏移。

eg:
(1)将读写位置移动到文件开头处:

1
2
3
off_t off = lseek(fd, 0, SEEK_SET);
if (off == -1)
return -1;

(2)将读写位置移动到文件末尾:

1
2
3
off_t off = lseek(fd, 0, SEEK_END);
if (off == -1)
return -1;

(3)将读写位置移动到偏移文件开头 100 个字节处:

1
2
3
off_t off = lseek(fd, 100, SEEK_SET);
if (off == -1)
return -1;

(4)获取当前读写位置偏移量:

1
2
3
off_t off = lseek(fd, 0, SEEK_CUR);
if (off == -1)
return -1;

函数执行成功将返回文件当前读写位置。