目录
2.文件流指针FILE *fp与文件描述符int fd的关系
FILE *open(const char *path , const char *mode);
const char *path:带有路径的要打开的文件名
const char *mode:文件的打开方式
r:只读;文件必须存在,否则打开失败
r+:可读可写;文件必须存在,否则打开失败
w:只写;文件不存在则会创建文件并打开,文件存在则会清空文件原有内容并打开
w+:可读可写;文件不存在则会创建文件并打开,文件存在则会清空文件原有内容并打开
a:追加只写;文件不存在则会创建文件并打开,文件存在则打开;并且写入数据总是会写入文件末尾
a+:可读追加写;文件不存在则会创建文件并打开,文件存在则打开;并且写入数据总是会写入文件末尾
b:以二进制方式打开文件,否则默认以文本形式打开文件
返回值:
成功,返回FILE*文件流指针(文件在代码中的操作句柄);失败,返回NULL
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
const void *ptr:要向文件写入的数据的首地址
size_t size:块大小
size_t nmemb:块个数
FILE *stream:fopen返回的文件流指针,表示要将数据写入到哪个文件
返回值:
返回实际写入文件的完整块个数(注意不是字节长度);出错返回0。
int fseek(FILE *stream, long offset, int whence);
FILE *stream:要操作的文件流指针
long offset:偏移量;正值,向后偏移;负值,向前偏移
int whence:标识开始偏移位置
SEEK_SET:起始位置
SEEK_CUR:当前读写位置
SEEK_END:末尾位置
返回值:
成功,返回0;失败,返回-1。
int fclose(FILE *fp);
返回值:
成功,返回0;失败,返回-1。
int ferror(FILE *stream);
测试文件的上一次操作是否出错,出错返回真。
int feof(FILE *stream);
测试文件读写是否到达文件末尾,到达返回真。
系统调用IO接口默认都是二进制操作。
int open(const char* pathname, int flags);
int open(const char* pathname, int flags, mode_t mode);
const char* pathname:要打开的文件的路径名
int flags:文件的打开方式
(
O_RDONLY:只读 O_WRONLY:只写 O_RDWR:可读可写
以上三种必须包含其一。
O_CREAT:文件不存在则创建文件;
O_APPEND:写入数据时以追加方式写入;
O_TRUNC:打开文件时,清空文件内容。
例:w方式可表示为:O_WRONIL | O_CREAT | O_TRUNC
)
mode_t mode:文件不存在时创建文件所使用的参数(文件的权限);若不需要创建文件,则这个参数可以不要
返回值:
成功,返回一个非负整数(文件描述符|文件的操作句柄);
失败,返回-1。
ssize_t write(int fd, const void *buf, size_t count);
int fd:open打开文件返回的文件描述符,标识要操作的文件
const void *buf:要写入的数据的首地址
size_t count:要写入文件的数据的字节长度
返回值:
成功,返回实际写入文件的数据长度;
失败返回-1。
ssize_t read(int fd, void *buf, size_t count);
int fd:open打开文件返回的文件描述符,标识要操作的文件
void *buf:一块空间首地址,用于存放读取到的数据
size_t count:要读取的数据长度,单位为字节
返回值:
成功,返回实际读取到的数据长度;
出错,返回-1。
off_t lseek(int fd, off_t offset, int whence);
int fd:文件的操作句柄
off_t offset:偏移量
int whence:开始偏移位置
SEEK_SET:起始位置
SEEK_CUR:当前读写位置
SEEK_END:末尾位置
返回值:
成功,返回当前跳转后的位置相对于起始位置的偏移量(通常跳转到文件末尾位置,就可获取文件长度)
出错,返回-1。
int close(int fd);
返回值:
成功,返回0;失败,返回-1。
文件描述符:当open打开一个文件时,返回的一个非负整数,它是一个文件的操作句柄。
那么文件描述符作为一个数字,是如何作为文件的操作句柄来标识文件的?
文件其实就是一块磁盘空间,给文件写入数据,实际上就是将数据写入到磁盘的指定位置。
因此当我们要操作一个文件时,必须要明确操作的是那块磁盘的哪个位置的数据。
★文件描述符的本质其实就是内核中,文件描述信息指针数组的下标。
通过文件描述符操作文件,实际上就是在内核中找到进行的files_struct结构体,根据下标在fd_arr描述信息指针数组中找到对应文件的描述信息地址,进行访问文件的描述信息,从而实现标识我们所要操作的文件。
文件流指针:
struct FILE* 是库函数的操作句柄
文件描述符:
int fd 是系统调用接口的操作句柄
库函数与系统调用接口的关系:
库函数封装了系统调用接口
所以文件流指针结构体FILE中,其实包含了文件描述符成员。
将原本要写入标准输出的数据,不再写入标准输出,而是写入指定文件中。
例:
相关知识:
一个程序运行,会默认打开三个文件:
标准输入0、标准输出1、标准错误2
关闭标准输入文件,打开的新文件会优先占据下标较小的空位置,也就是temp.txt对应的文件描述符会是1,那么此时本来要写入标准输出的数据会被写到temp.txt中。
运行程序后,内容没有打印。
而是写入到了temp.txt文件中。
int dup2(int oldfd, int newfd);
让newfd拷贝oldfd位置的文件描述信息指针,作用相当于让oldfd和newfd都操作oldfd所对应的文件。
例:
效果相同,且不需要关闭旧的文件,更加灵活安全。
动态库与静态库:都是针对典型功能已经封装好的接口的打包文件
程序编译四个阶段:预处理、编译、汇编、链接
链接方式:
1)动态链接:
链接动态库,把库中函数的位置信息记录到可执行程序中。
2)静态链接:
链接静态库,将库中用到的代码写入到可执行程序中。
1)将各自的.c代码生成二进制指令
gcc -fPIC -c file.c -o file.o
2)打包生成库文件
动态库:
gcc -shared file.o -o libfile.so
静态库:
ar -cr libfile.a filr.o
gcc -l 选项--指定链接库名称
gcc file.c -o file -lmylibfile
链接方法:
1.将库文件放到指定目录下:/usr/lib64/
2.设置环境变量,将库文件所在路径添加到环境变量中:LIBRARY_PATH=${LIBRARY_PATH}:./
3.使用gcc -L选项指定库文件默认链接路径(主要针对静态库使用):gcc file.c -o file -L/ -lmylibfile
链接方法:
1.将库文件放到指定目录下:/usr/lib64/
2.设置环境变量:LD_LIBRARY=${LD-LIBRARY_PATH}:./