用于打开或者创建一个文件。用man open命令查看
函数原型:
#include
#include
#include
int open(const char *pathname, int flags);
参数说明:
pathname 打开的文件
flags 是打开方式:
- O_RDONLY 以只读方式打开
- O_WRONLY以只读方式打开
- O_RDWR以读写方式打开
- O_TRUNC 文件清空
- O_APPEND 文件追加
返回值:
- 成功:返回文件描述符
- 失败:-1
open也可以用来创建文件,函数原型为
int open(const char *pathname, int flags, mode_t mode);
参数说明:
int fd=open("abc",O_RDONLY);
printf("fd=%d\n",fd);
输出结果:fd=3
stdin 0 是标准输入
stdout 1 是标准输出
stderr 2 是标准错误
从fd所指文件中读取数据到buf所指的空间,空间大小为len。用man 2 read命令查看
函数原型:
#include
ssize_t read(int fd, void *buf, size_t len);
参数说明:
- fd:文件描述符
- buf:读到哪里去
- len:空间多大
返回值:实际读取的字节数
往fd所指文件中写入数据,数据的起始地址为buf,大小为len.
函数原型:
#include
ssize_t write(int fd, const void *buf, size_t len);
函数原型:
#include
#include
off_t lseek(int fd, off_t offset, int whence);
参数说明:whence 从哪个地方开始偏移
- SEEK_SET 文件开头
- SEEK_CUR 当前位置
- SEEK_END 文件末尾
返回值:新的相对于文件开头的偏移量。
例题1:
int lseek(fd,2,SEEK_CUR)
含义是 向后偏移两个字节,返回SEEK_CUR到文件开头的距离。
例题2:如何求文件大小??
lseek(fd,0,SEEK_END)
含义为从文件头到文件尾的字节数,也就是文件大小。
关闭一个文件。用man close命令查看
函数原型:
#include
int close(int fd);
返回值:成功返回0;失败返回-1。
fd与FILE的对比:
操作系统用一个整数代表打开的文件。进程能打开的文件描述符个数为[0,ulimit -n],ulimit -n是一条命令,可以查看系统最大打开文件个数。
fd在open时产生的,起到一个索引的作用。进程通过PCB中的文件描述符表找到该fd所指向的文件指针file。因此在Linux系统下面,文件描述符主要是被用来标识一个文件。内核通过文件对象表来管理系统中各种各样的文件,而文件表则是通过指针来指向打开的文件,进而达到管理整个文件系统的目的。
int fileno(FILE * stream)
FILE * fdopen(int fd, const char * mode)
typedef struct _iobuf {
char *_ptr; //缓冲区当前指针
int _cnt;
char *_base; //缓冲区基址
int _flag; //文件读写模式
int _file; //文件描述符
int _charbuf; //缓冲区剩余自己个数
int _bufsiz; //缓冲区大小
char *_tmpfname;
}FILE;
C语言中这样获取文件指针
FILE * fp=fopen("test.txt","r");
获取到指针以后,我们就可以获得指针当中文件描述符的信息。
注意:
文件描述符是唯一的,但是文件指针不是唯一的,文件指针指向的对象是唯一的。
其实,除此之外,我们也应该清楚文件描述符fd和文件指针FILE在系统中所处的位置:
文件描述符:OS层
文件指针:lib层(C库)
lib库是在操作系统上为用户所做的更高一层封装。
封装主要体现在:
(1)缓冲方式:操作系统一般采用的是无缓冲,而lib一般则采用的是全缓冲的方式。
(2)函数封装:在lib层所对应的标准输入std_in,标准输出std_out,标准错误std_err也正好对应着文件描述符的0,1,2。