理解库函数和系统调用
- 上面的 fopen fclose fread fwrite 都是C标准库当中的函数,我们称之为库函数(libc)。
- 而, open close read write lseek 都属于系统提供的接口,称之为系统调用接口
我们先看下面一张图:
由图可以看出:库函数是对系统调用接口的一种封装
库函数IO接口
fopen / fread / fwrite / fseek / fclose — FILE*
fopen
FILE *fopen(char *filename, char *mode);(文件名称,打开方式)
打开方式:
- r 只读
- r+ 读写
- w 只写
- w+读写
- a 追加写
- a+ 追加读写
- b 二进制操作
追加写:每次写入数据总是写入到文件末尾
注意:
- r+的读写和w+的读写有什么区别??
- r+读写打开文件,若文件不存在则报错;
- w+读写打开文件,若不存在则创建,若存在清空原有内容(w/w+每次都会清空文件原有内容后写入数据)
-
a 不仅仅是追加写,若文件不存在还会创建新文件
-
b 默认清空如果不指定b,则认为文件是文本操作,加上b则认为是二进制操作
区别在于有一个特殊字符,只是一个字符,但占据两个字节的内存(读取100个字节大小的文件,文本操作最终读取出来的数据,不一定是100个字节) -
返回值: 返回一个FILE*的文件留置针作为文件的操作句柄;失败返回NULL
fread、fwrite
size_t fread(char *buf, size_t block_size, size_t block_count, FILE* fp);(缓冲区,块大小,块个数,文件流指针)
size_t fwrite(char *data, size_t block_size, size_t block_count, FILE* fp);(数据首地址,块大小,块个数,文件流指针)
注意:
- bread/fwrite操作的数据实际大小是 块大小*块个数 ; 块大小=10, 块个数=2;意味着要写入/读取20个字节的数据
- 返回值:返回实际操作的块个数 例如:独取一个文件size =10; count = 2;
如果文件大小足够则返回2 / 但是若文件大小只有16字节,组会返回1,因为第二块没有读满 - fread 如果读到了文件末尾会返回0;若读取1000个字节,数据块个数(count)为1, 数据块大小(size)只有512字节, 虽然读了512字节也会返回0
fread / fwrite比较推荐数据块大小为1, 数据块个数是想要操作的数据长度
对文件数据进行字符串操作的时候要注意文件数据中的\0这种数据
fseek
int fseek(FILE *fp, long offset, int whence);(将文件的读写指针从whence位置偏移offset个字节) — 跳转文件读写位置
fseek 跳转读写位置
- SEEK_SET 从文件起始位置偏移
- SEEK_CUR 从文件当前读写位置偏移
- SEEK_END 从文件末尾偏移
fseek:文件没有数据也可以跳转读写位置
fclose
int fclose(FILE *fp); 关闭文件流指针,释放资源
系统调用IO接口
open/read/write/lseek/close
open
int open(char * filename, int flag, mode_t mode);
-
filename:要打开的文件名称
-
flags:选项参数 (文件的打开方式 )
必选项:
O_RDONIY / O_WRONLY / O_RDWR 只读/只写/可读可写 (三种只能选择其一)可选项:
- O_CREAT 文件不存在则创建新文件,存在则打开
- O_EXCL 跟 O_CREAT同时使用,文件不存在则创建,存在则报错
- O_TRUNC 打开文件的同时清空原有内容
- O_APPEND 追加写,总是将数据写入到文件末尾
使用O_CREAT就一定要通过open函数的第三个参数指定文件的创建权限
-
mode:权限 - -若使用了O_CREAT有可能创建新文件,就一定要指定文件权限,八进制数字(mode—权限0664 给定&~umask)
-
返回值: 一个非负整数(文件描述符 )
write
ssize_t write(int fd, char *buf,size_t count);
-
fd:open返回的文件描述符(文件操作句柄)
-
buf:要写入文件的数据的空间首地址
-
count:要写入的数据大小
-
返回值:返回实际写入文件的数据字节长度;失败返回-1
read
ssize_t read(int fd, char *buf,size_t len);
-
fd:open返回的文件描述符
-
buf:从文件中读取数据放到缓冲区中的首地址
-
len:想要读取的数据长度,注意len不能大于缓冲区的大小
-
返回值:返回实际写入文件的数据字节长度;失败返回-1
lseek
off_t lseek(int fd, off_t offset, int whence);
-
fd:open返回的文件描述符
-
offset:偏移量
-
whence:从哪里开始偏移
- SEEK_SET 从文件起始位置
- SEEK_CUR 从文件当前读写位置
- SEEK_END 从文件末尾
-
返回值:成功返回当前位置相对于起始位置的偏移量;失败返回-1
close
int close(int fd); 通过文件描述符关闭文件,释放资源
如果对这些函数的解析不充分的话可以使用 man
手册
如有不同见解,欢迎留言讨论~~