文件IO(又称系统IO)

posix(可移植操作系统接口)定义的一组函数,Linux系统下,标准IO基于文件IO实现

不提供缓冲机制,每次读写操作都会引起系统的调用,其核心概念是文件描述符

操作 标准IO 文件IO
打开文件 fopen open
关闭文件 fclose close
读取文件 getc、fgetc、gets、fgets、getchar、fread read
写入文件 putc、fputc、puts、fputs、putchar、fwrite write

文件描述符

  • 每打开一个文件都有对应的一个文件描述符(非负整数),其从0开始分配,依次递增,进行文件IO操作时即通过文件描述符来完成

  • 0(标准输入),1(标准输出),2(标准错误)是每个程序默认占用这三个文件描述符,后面打开的文件从3开始递增

文件IO的函数

open函数

用来创建或打开一个文件,在<fcntl.h>头文件中被定义

1
2
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
  • 返回值:打开成功后返回文件描述符,出错时返回EOF
  • 可以打开设备文件,但不能创建设备文件(创建设备在mknode驱动部分)
  • pathname:创建或打开的文件名称(包括文件路径)
  • flags:文件的打开方式
  • mode(8进制表示法):一般用于创建文件时指定新文件的权限,其指定的权限受限于umask值的影响
flags参数 说明(O_RDONLY,O_WRONLY,O_RDWR这三个参数互斥)
O_RDONLY 只读方式打开文件
O_WRONLY 可写的方式打开文件
O_RDWR 读写的方式打开
O_CREAT 文件不存在时,创建新文件,并使用mode参数设置权限
O_EXCL 若使用O_CREAT时文件存在,则返回错误信息
O_NOCTTY 若文件为终端,则不可调用open()系统调用的那个进程的控制终端
O_TRUNC 若文件存在,打开文件时会先删除文件的原有数据
O_APPEND 以添加的方式打开文件,在文件末尾进行写操作

umask:用来设定文件或目录的初始权限

文件或目录的初始权限 = 文件或目录的最大默认权限 - umask权限

close函数

用于关闭一个打开的文件,在头文件unistd.h中被定义

1
int close(int fd);
  • 返回值:成功时返回0,错误时返回EOF
  • 程序结束时自动关闭所有打开的文件,文件关闭后,文件描述符不再代表文件

read函数

用于读取文件数据,在unistd.h头文件中被定义

1
ssize_t read(int fd, void *buf, size_t count);
  • 返回值:成功返回实际读取的字节数,错误时返回EOF
  • 读到文件末尾时返回0
  • buf:数据接收到缓冲区
  • count不应超过buf大小

write函数

用于向文件写入数据,在unistd.h头文件中被定义

1
ssize_t write(int fd, void *buf, size_t count);
  • 返回值:成功返回实际写入的字节数,错误返回EOF
  • buf是送数据的缓冲区
  • count不应该超过buf的大小

lseek函数

用于定位文件,在unistd.h头文件中被定义

1
off_t lseek(int fd, off_t offset, int whence)
  • 返回值:成功时返回当前的文件读写位置,出错返回EOF
  • offset:位置偏移量
  • whence参数:SEEK_SET(文件开头偏移)、SEEK_CUR(以当前位置往后增加)、SEEK_END(文件尾增加偏移量)

目录操作函数

opendir和fdopendir函数

用于打开一个目录文件,在dirent.h中被定义

1
2
DIR *opendir(const char *name);
DIR *fdopendir(int fd); // 配合open函数使用
  • 返回值:成功时返回目录流指针,出错时返回NULL
  • DIR是描述打开的目录文件的结构体类型

readdir函数

用于读取目录流中的内容,在dirent.h中被定义

1
struct dirent *readdir(DIR *dirp);
  • 返回值:成功时返回dirp目录流中的下一个目录项,出错或到末尾时返回NULL
  • struct dirent是描述目录流中的一个目录项的结构体类型
  • 成员有char d_name[256],其存储目录中的文件名

closedir函数

用于关闭一个目录文件,在dirent.h头文件中被定义

1
int closedir(DIR *dirp);
  • 返回值:成功时返回0,出错时返回EOF

文件属性和权限

chmod和fchmod函数

用于修改文件的访问权限,在sys/stat.h中被定义

1
2
int chmod(const char *path, mode_t mode);
int fchmode(int fd, mode_t mode); // 和open函数配合使用
  • 返回值:成功时返回0,错误时返回EOF
  • root和文件所有者可以修改文件的访问权限

stat、lstat、fstat函数

用于获取文件的属性,在sys/stat.h头文件中被定义

1
2
3
int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
  • 返回值:成功时返回0,出错时返回EOF
  • 如果path是符号链接stat获取的是目标文件的属性;而lstat获取的是链接文件的属性
    stat函数返回结构体如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct stat {
dev_t st_dev; // 文件设备编号
ino_t st_ino; // 节点号
mode_t st_mode; // 文件类型和权限
nlink_t st_nlink; // 硬链接数目
uid_t st_uid; // 用户ID
gid_t st_gid; // 组ID
dev_t st_rdev; // 设备类型,若为设备文件则为设备编号
off_t st_size; // 文件字节大小
blksize_t st_blksize; // 块大小,文件系统的I/O缓冲区大小
blkcnt_t st_blocks; // 分配的块数
time_t st_atime; // 最后一次访问时间
time_t st_mtime; // 最后一次修改时间
time_t st_ctime; // 最后一次改变属性的时间
}

文件类型判断

参数宏 说明
S_IFMT 0170000 文件类型的位遮罩
S_ISREG(st_mode) 0100000 是否为常规文件
S_ISDIR(st_mode) 0040000 是否为目录
S_ISCHR(st_mode) 0020000 是否为字符设备
S_ISBLK(st_mode) 0060000 是否为块设备
S_ISFIFO(st_mode) 0010000 是否为FIFO文件
S_ISLINK(st_mode) 0120000 是否为链接文件
S_ISSOCK(st_mode) 0140000 是否为SOCKET文件