目录
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);
int creat(const char* pathname,mode_t mode);
如果文件打开失败, open 将返回 -1 ,程序需要对异常情况进行处理。导致打开文件的原因又很多,例如:文件不存在;抑或权限不足等等。
flags字段使用POSIX的几个宏,此时必须包含头文件<fcntl.h>
才行。
可以是下面几个宏的逻辑或组合。这些宏共有三种类型:
访问方式 | 描述 |
---|---|
O_RDONLY | 只读 |
O_WRONLY | 只写 |
O_RDWR | 可读写 |
打开时标志 | 描述 |
---|---|
O_CREAT | 创建文件,需要指定第3个参数mode |
O_EXCL | 与O_CREAT 联用,如果文件已存在则返回错误 |
O_TRUNC | 将清空文件的内容,仅对普通文件有用 |
O_NOCTTY | 若打开的文件是终端设备,不让它作为该进程的控制终端 |
O_NOBLOCK | 以非阻塞模式打开 |
IO操作方式 | 描述 |
---|---|
O_APPEND | 把数据写到文件末尾 |
O_NONBLOCK | 对文件的read()/write(),当无立即可用输入(或输出不能立即写出)时能以EAGAIN错误状态标志立即返回 |
O_ASYNC | (异步)此标志被设置,文件描述符有输入数据时会生成SIGIO信号 |
O_SYNC | |
O_DSYNC | |
O_RSYNC |
可以查看man 2 open
read
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
参数 | 描述 |
---|---|
fd | 文件描述符 |
buf | 读取的数据存放在buf指针指向的缓冲区 |
count | 读取的字节数 |
若果函数执行成功,返回读取的字节数,如果遇到EOF,则返回0。出错返回**-1**,并设置相应errno值。
- 当我指定要读取100个字节的时候,在读完30个字节后,遇到了EOF,那么这时立即返回30,接下来继续执行read函数的时候返回0。
- 从终端设备读,通常以行为单位,读到换行符就返回。
- 当出错时(即返回-1),如果errno的值是EINTR,表示遇到调用信号而中断了读取,那么我们可以再次尝试read。
write
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
参数同read函数
参数 | 描述 |
---|---|
fd | 文件描述符 |
buf | 读取的数据存放在buf指针指向的缓冲区 |
count | 读取的字节数 |
如果函数调用成功,返回值为写入的字节数;否则返回值为**-1**,并设置相应的errno值。
lseek
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
在内核中对一个文件描述符(fd)的偏移量只维护一个值,也就是说你用读写方式打开一个文件,如果先用read读取了n个字符,紧接着用write写入了n个字符,那么后来写入的n个字符并不是从文件第一个字符位置开始的,而是从n+1个字符位置开始的。所以通常我们需要使用lseek来使fd的偏移量置于文件开始位置。
access
函数用来判断用户是否具有访问某个文件的权限(或判断某个文件是否存在)。
#include<unistd.h>
int access(const char *pathname,int mode)
pathname:是文件的路径名+文件名(例:/home/book/file.txt)
mode:以下参数可选
F_OK 值为0,判断文件是否存在
X_OK 值为1,判断对文件是可执行权限
W_OK 值为2,判断对文件是否有写权限
R_OK 值为4,判断对文件是否有读权限
注:后三种可以使用或“|”的方式,一起使用,如W_OK|R_OK
若测试成功则返回0,否则返回-1
fcntl
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
参数可能有两个,也可能有三个,具体看第二个参数的取值。
- fd: 文件描述符
- cmd: 命令
- arg: 命令的参数
常用cmd | arg | 描述 |
---|---|---|
F_DUPFD | 复制文件描述符 | |
F_GETFD | 无 | 获取文件描述符标签 |
F_SETFD | 设置文件描述符标签 | |
F_GETFL | 获取文件状态标签 | |
F_SETFL | 设置文件状态标签 | |
F_GETFLK | 获取文件锁 | |
F_SETFLK | 设置文件锁 | |
F_SETLKW | 类似F_SETLK,但等待完成 | |
F_GETOWN | 获取收到SIGIO信号的进程或进程组ID | |
F_SETOWN | 设置接收SIGIO信号的进程或进程组ID |
文件描述符标签
文件描述符标签(flags)是一个整型,它的每一个二进制为,表明一种标志。
复制的文件描述符,标签不会被复制,每个文件描述符有各自的标签
当前,只有一个标志FD_CLOEXEC,表明当执行exec()函数时,将关闭该文件描述符。默认情况下,此位是清除的,所以在执行exec()之后,之前的文件描述符会保留。
fcntf(fd,F_SETFD,FD_CLOEXEC);//设置c该标志,但是其他标志就消失了。
//良好的写法是:
int oldflags = fcntl(fd,F_GETFD);
oldflags |= FD_CLOEXEC;//设置该标志
fcntl(fd,F_SETFD,oldflags);
//如果要清除该标志
oldflags &= ~FD_CLOEXEC;
文件状态标签被所有复制的文件描述符共享。表明文件打开的属性,也就是open()的flags参数所指明的。
当判断一个文件的读写标志时,不能简单的通过**&操作来判断,因为文件的读写标志有三种状态,系统中并非设置了三个独立位来表示,实际上是用了两个位来表示的。所以最好使用O_ACCMODE**(0x3)来进行**&操作。
其他的标志可以直接用&**来判断,如flags&O_APPEND
dup
复制文件描述符号
#include <unistd.h>
int dup(int oldfd);
int dup2(int oldfd, int newfd);
dup参数是一个文件描述符,返回一个文件描述符,值是当前未使用的最小数字,指向的位置和参数相同。
dup2,可以自己指定要返回的文件描述的数值newfd,如果newfd是一个已经打开的文件描述符,则会将其关闭。
另外还有dup3(),不常用。
dup2(fd,fd2);
//等价于
close(fd2);
fcntl(fd,F_DUPFD,fd2);
功能上可以等价于close()和fcntl()的组合,但是dup2是一个原子操作(关闭fd2,和复制fd不会被中断)。