Linux环境编程第三天笔记
标准文件I/O与系统文件I/O
-
系统文件I/O是Linux内核提供的系统调用函数,无缓冲机制,直接与内核交互。
-
标准文件I/O是基于C标准库,实现的函数,在用户空间维护缓冲区
效率:标准I/O > 系统文件I/O
各类文件
在Linux中,文件分为7种
| 文件类型 | ls -l下的文件类型缩写 | 特点 |
|---|---|---|
| 普通文件 | - | 存在于外部存储器种,用于存储普通数据 |
| 目录文件 | d | 用于存放目录项,是文件系统管理的重要文件类型 |
| 管道文件 | p | 用于进程间通信的特殊文件,也称命名通道FIFO |
| 套接字文件 | s | 用于网络间通信的特殊文件 |
| 链接文件 | l | 用于间接访问另外一个目标文件,相当于Windows的快捷方式 |
| 块设备文件 | b | 块设备在应用层的访问接口 |
open和openat
调用open或openat可以打开或创建一个文件。
返回值:若成功,返回文件描述符,若失败,返回-1。
#include <fcntl.c>
int open(const char *path,int oflag);
int open(const char *path,int oflag,mode_t mode);//mode为八进制权限
int1 openat(int fd,const char *pa1th,int oflag)
path是打开或创建的文件名,oflag是函数的选项
| 情况 | path类型 |
fd参数 |
|
|---|---|---|---|
| 1 | 绝对路径 | 任意值 | fd被忽略,openat等价于open |
| 2 | 相对路径 | 已打开的目录fd | 相对于该目录文件描述符指向的目录 |
| 3 | 相对路径 | AT_FDCWD |
相对于进程的当前工作目录 |
| oflag的值 | 效果 |
|---|---|
| O_RDONLY | 以只读的形式打开文件 |
| O_WRONLY | 以只写的形式打开文件 |
| O_RDWR | 以读/写的形式打开文件 |
| O_CREAT | 若文件不存在,创建文件 |
| O_EXCL | 如果使用O_CREAT选项且文件存在,返回错误信息 |
| O_NOCTTY | 如果文件为终端,那么终端不可以作为调用open()系统调用的那个进程的控制信息 |
| O_TREAT | 如果文件已经存在,则删除文件中原有数据 |
| O_APPEND | 以追加的形式打开文件 |
// 场景2:使用目录fd
int dir_fd = open("/home", O_RDONLY | O_DIRECTORY);//打开目录
int fd4 = openat(dir_fd, "user/file.txt", O_RDONLY);
// 在/home/user/file.txt
// 场景3:使用openat + AT_FDCWD
int fd2 = openat(AT_FDCWD, "data.txt", O_RDONLY);//默认工作目录为进程的启动目录
// 场景3:改变当前工作目录后
chdir("/tmp");
int fd3 = openat(AT_FDCWD, "temp.txt", O_RDONLY);
// 在/tmp目录下打开temp.txt
close
可以调用close关闭一个打开的文件。
返回值:若成功,返回0,若失败返回-1
#include <unistd.h>
int closen (int fd);
关闭一个文件时还会释放该进程加在该文件上的所有记录锁。
当一个进程终止时,内核自动关闭它所有的打开文件。
lseek
每个打开的文件都有一个与其相关联的"当前文件偏移量",通常读写操作都从当前文件偏移量处开始,当打开一个文件时,偏移量默认为0。
lseek可以显示地为一个打开文件设置偏移量。
返回值:若成功,返回新的文件偏移量,若失败,返回-1。
#include <unistd.h>
off_t lseek(int fd,off_t offset,int whence);
| whence 值 | 常量定义 | 含义说明 | 偏移量计算公式 | offset 取值范围 |
|---|---|---|---|---|
| SEEK_SET | 0 | 从文件开头开始偏移 | 新偏移量 = offset | offset ≥ 0(通常,负值可能导致错误) |
| SEEK_CUR | 1 | 从当前位置开始偏移 | 新偏移量 = 当前偏移量 + offset | 可正可负(正数向后,负数向前) |
| SEEK_END | 2 | 从文件末尾开始偏移 | 新偏移量 = 文件长度 + offset | 可正可负(正数超过文件尾,负数向前) |
通过返回值可以用来测试文件是否可以设置偏移量
文件偏移量可以大于等于文件当前长度,这种情况下,文件下次写将加长该文件。
文件中未被写的字节都被读为0。
read
read函数可以从打开的文件中读数据
返回值:成功:读到字节数(若已到文件尾,返回0),失败:返回-1
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
参数buf为用户申请的缓冲区,参数count为要读取的字节数。
当从终端开始读时,通常最多一次读一行(如果标准输出是连接到终端,则它是行缓冲的,否则是全缓冲的)。
write
write可以向打开的文件写入数据
返回值:成功:返回写入的字节数;失败:返回-1
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
参数buf为用户申请的缓冲区,参数count要写入的字节数。
对于普通文件,写操作从文件当前偏移量处开始。
ioctl和fcntl
除非不得已,否则尽量使用fcntl。
#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);
-
fd:文件描述符(通常是设备文件) -
request:请求码(设备特定) -
...:可变参数,通常是指向数据的指针
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
| 命令字 cmd | 变参 arg | 含义 |
|---|---|---|
| F_DUPFD | long arg | 复制一个在数值上大于或等于 arg 并未使用的文件描述符,并且使其代表与 fd 相同的文件 |
| F_DUPFD_CLOEXEC | long arg | 作用和 F_DUPFD 一样,但新复制的描述符的 FD_CLOEXEC 状态会被置为 1 |
| F_GETFD | void | 获取 FD_CLOEXEC 状态 |
| F_SETFD | long arg | 设置 FD_CLOEXEC 状态,若该状态位为 0 则意味着该 fd 在程序执行 execve () 加载新代码时将保持有效,否则该 fd 在新代码执行时将被关闭 |
| F_GETFL | void | 获取 status 状态 |
| F_SETFL | long arg | 设置 status 状态 在 Linux 中,以下选项不可设置: O_RDONLY、O_WRONLY、O_RDWR、O_CREAT、O_EXCL、O_NOCTTY、O_TRUNC 以下的选项可以设置: O_APPEND、O_ASYNC、O_DIRECT、O_NOATIME、O_NONBLOCK |
| F_SETLK | struct flock *arg | 将 arg.l_type 设置为以下值意味着加锁: FD_RDLCK、FD_WRLCK 将 l_type 设置为以下值意味着解锁: FD_UNLCK 如果当前区域已经有冲突的锁存在,那么将立即返回 - 1,且 errno 将被设置为 EACCES 或 EAGAIN |
| F_SETLKW | struct flock *arg | 和 F_SETLK 一样,但在冲突的情况下将会阻塞等待 |
| F_GETLK | struct flock *arg | 用 arg 中的信息检查是否有冲突,如果无冲突,则将 arg.l_type 设置为 FD_UNLCK,别的成员保持不变;如果有冲突,则 arg 将会储存当前冲突的锁的相关信息 |
| F_GETOWN | void | 获取收到由 fd 输入或输出状态改变而触发的信号 SIGIO 和 SIGURG 的进程或进程组 ID。进程 ID 用正整数表示,进程组 ID 用负整数表示 |
| F_SETOWN | long arg | 设置接收由 fd 输入或输出状态改变而触发的信号 SIGIO 和 SIGURG 的进程或进程组 ID 为 arg。进程 ID 用正整数表示,进程组 ID 用负整数表示 |
| F_GETOWN_EX | struct f_owner_ex *arg | 作用同 F_GETOWN,但还能获取线程的 TID,且只能适用于 Linux-2.6.32 及以后的版本 |
| F_SETOWN_EX | struct f_owner_ex *arg | 作用同 F_SETOWN,但还能设置线程的 TID,且只能适用于 Linux-2.6.32 及以后的版本 |
| F_GETSIG | void | 获取由 fd 输入或输出状态改变而触发的信号 |
| F_SETSIG | long arg | 设置由 fd 输入或输出状态改变而触发的信号 |
| F_GETPIPE_SZ | void | 获取管道文件缓冲区的大小 |
| F_SETPIPE_SZ | long arg | 设置管道文件缓冲区的大小为 arg。arg 必须介于 Linux 内存页大小和系统支持的最大尺寸(见 /proc/sys/fs/pipe-size-max)之间 |
mmap
mmap可以在进程的虚拟内存空间种映射出一块内存区域,并指定一个文件,用文件数据初始化这块内存,文件数据和内存中的数据一一对应
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
| 参数 | 说明 |
|---|---|
| addr | 内存映射的起始地址。 如果该参数为NULL,则系统将会自动寻找一个合适的起始地址 如果该参数为NULL,则系统会以此为依据寻找一个合适的起始地址。在Linux中一般为页地址的整数倍 |
| length | 映射区域的大小(字节) |
| prot | 内存保护标志(按位或) PROT_EXEC :可执行 PROT_READ :可读 PROT_WRITE :可写 PROT_NONE :不可访问 |
| flags | 映射类型和特性(按位或) |
| fd | 文件描述符(匿名映射时为-1) |
| offset | 文件映射的偏移量(必须是页大小的倍数) |