1. C语言的文件操作接口
头文件:#include <stdio.h>
fopen, fread, fwrite, fseek , fclose
1.1 fopen
FILE *fopen(const char *path, const char *mode);
path:待要打开的文件
mode:以何种方式打开
r:可读方式打开
r+:可读可写方式打开
w:可写方式打开
w+:可读可写方式打开,如果文件不存在,则创建文件;如果是打开了一个已经存在的文件,则截断文件(清空文件内容)
a:追加写,但是不可以读,如果文件不存在则创建文件;如果文件存在,则在文件的末尾开始追加写
a+:追加写,可以读,如果文件不存在,则创建文件;如果文件存在,则在文件的末尾开始追加写
返回值:成功则返回文件留置针FILE;失败则返回NULL
1.2 fread
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
ptr:将从文件读到的内容保存到 ptr 指向的空间中
size:定义读文件时,一个块的大小,单位为字节
nmemb:期望可以从文件读多少块
size * nmemb:相当于期望从文件当中读多少字节
stream:文件流指针
返回值:返回的是真正读取到块的个数
常见用法:将一块的大小定义为1字节,nmemb就是读的字节的多少,返回的既是块数也是字节数
1.3 fwrite
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
ptr:想要往文件中写什么内容
size:定义往文件当中写的块的大小,单位为字节
nmemb:期望写多少块
stream:文件流指针
返回值:返回成功写入到文件中的块的个数
常见用法:定义块的大小为1字节,nmemb则为想要写入的字节数量,返回值则为成功写入的字节数量
1.4 fseek
int fseek(FILE *stream, long offset, int whence);
stream:文件流指针
offset:偏移量
whence:将文件流指针偏移到什么位置
SEEK_SET:定义文件流指针到文件头部
SEEK_CUR:定义文件流指针到当前位置
SEEK_END:定义文件流指针到文件末尾
作用:移动文件流指针指向的位置
1.5 fclose
int fclose(FILE *fp);
1.6 示例
偏移量为1,不是从下标为0处开始读,而是从下标为1处开始读
fseek是库函数,lseek是系统调用函数,fseek为了实现自己的动作会去调用lseek
2. 系统调用的文件操作接口
头文件:open:#include <fcntl.h>
其他:#include <unistd.h>
2.1 open
2.1.1 打开的文件存在,则使用下面的接口
int open(const char *pathname, int flags);
pathname:待要打开的文件
flags:以何种方式打开
O_RDONLY:只读方式打开
O_WRONLY:只写方式打开
O_RDWR :读写方式打开
以上三个有且只能存在一种,必须有其中一个可选项:
O_TRUNC:截断文件(清空文件内容)
O_CREAT:文件不存在则创建文件
O_APPEND:追加的方式
O_EXCL | O_CREAT:如果文件存在,则打开文件失败
使用按位或的方式进行组合
O_RDWR | O_CREAT | O_APPEND
本质上内核是使用位图的方式来表示每一种方式的
2.1.2 打开的文件不存在,则使用下面的接口
int open(const char *pathname, int flags, mode_t mode);
mode:当文件是新打开的一个文件,则需要给文件设置权限,设置权限的时候,则传递一个8进制的数字就可以
返回值: 成功:返回一个文件描述符
失败:返回-1
2.2 read
ssize_t read(int fd, void *buf, size_t count);
ssize_t:有符号整型;size_t:无符号整型
fd:文件描述符
buf:将文件内容读到buf指向的空间当中
count:期望读多少字节
返回值:返回读到的字节数量
2.3 write
sszie_t write(int fd, const void *buf, size_t count);
fd:文件描述符
buf:将buf指向的内容写到文件当中去
count:期望写多少字节
返回值:返回写入的字节数量
2.4 lseek
off_t lseek(int fd, off_t offset, int whence);
fd:文件描述符
offset:偏移量
whence:
SEEK_SET:偏移到文件头部
SEEK_CUR:偏移到当前位置
SEEK_END:偏移到文件末尾
2.5 close
close(int fd);
关闭文件描述符
2.6 示例
3. 文件描述符
文件描述符的本质
在task_struct结构体当中有一个结构体指针files_struct * files,files_struct * files指向了一个结构体files_struct,结构体当中有一个数组fd_array[],数组元素的类型是指针struct file*,struct file *指向了一个结构体struct file,struct file保存的是文件的源信息,包括文件名称、文件大小、iNode节点号、文件权限、文件所有者、文件所属组、文件时间,这些信息就对应磁盘当中的某一个文件
文件描述符是一个正整数,原因就是因为是一个数组的下标
说明文件描述符是顺序分配的,0是标准输入,1是标准输出,2是标准错误
文件描述符的分配方式是:最小未分配原则
4. 文件描述符和文件流指针的区别
文件流指针代码本质
一个文件流指针只能保存一个文件描述符
C标准库对应的缓冲区:读缓冲区&写缓冲区
文件流指针和文件描述符的关系:文件流指针包含文件描述符
exit和_exit函数的区别:刷新缓冲区,指的就是struct _IO_FILE结构体当中的缓冲区
5. 重定向
5.1 重定向的本质
重定向的符号: >:清空重定向
>>:追加重定向
从文件描述符的角度理解重定向
5.2 重定向的接口
int dup2(int oldfd, int newfd);
newfd拷贝oldfd的值,将newfd重定向为oldfd
返回值:
成功:需要做两件事,(1)关闭newfd,(2)让newfd指向oldfd
失败:(1)oldfd是一个非法的文件描述符,或者不存在的文件描述符,函数调用失败,并且没有关闭newfd;
(2)newfd和oldfd的值是相等的,则dup2函数什么事也没有干,所在在开始的时候判断一下newfd 和oldfd是否相等
5.3 重定向的实现代码
6. 动态库和静态库
动态库和静态库都是程序代码的集合,将代码集合封装在了库文件当中,提供给调用者使用。
举例:微信当中有很多功能,他写的代码不仅供自己使用,还要供调用者使用,比如美团点餐需要支付,支付时你选择微信支付,就会跳转到微信支付界面,支付完再跳回美团界面。本质上是微信给美团预留了调用接口,也就是提供了某些函数,但是并不会把源码给你,会把实现的那些代码封装到一个库里面,把这个库提供给别人使用,需要提供两个东西,一个是当前的库所对应的头文件,头文件中是这些函数的声明,另一个是头文件所对应的函数库。在需要使用别人函数的时候只需要把头文件包含进来就可以了,在编译阶段,把这个库编译到可执行程序当中
6.1 动态库
特征: win:后缀为 .dll
linux:前缀:lib,后缀为 .so
生成:使用gcc/g++编译命令,需要用到两个命令行参数
-fPIC:产生位置无关的代码
-shared:产生共享库
创建一个动态库
使用:
gcc/g++的命令行参数
-l[库文件名称(去掉前缀、后缀的名称)]:链接某个库文件
-L [path]:指定当前链接库文件所在路径
都有哪些方式可以使自己的可执行程序找到自己依赖的动态库?
(1) 将动态库放到可执行程序的路径下
(2) 配置LD_LIBRARY_PATH环境变量:临时生效,推荐做法
动态库的环境变量: LD_LIBRARY_PATH
(3) 放到系统库的路径下,/lib64:极力不推荐
6.2 静态库
特征: Win:后缀为 .lib
Linux:前缀为 lib,后缀为 .a
生成:注意点:使用目标文件进行编译生成
第一段:使用gcc/g++将源代码文件编译成为目标文件(.o文件)
第二段:使用ar -rc命令编译目标文件生成静态库
必须是目标文件(print.o)生成静态库(libprint.a),虽然可以用源文件(print.c)生成静态库,但是在使用的时候会出错。出现以下的错误
并没有发现静态库在里面,那是因为静态库已经被编译到可执行程序当中
当把这个静态库移动到上级目录,再执行这个可执行程序,依然能运行,因为库已经被编译到可执行程序中,已经不依赖这个静态库了。
6.3 区分动态库、静态库、静态链接、动态链接
动态库和静态库是一种库文件
动态库:win:后缀:.dll linux:前缀:lib,后缀:.so
静态库:win:后缀:.lib linux:前缀:lib,最后:.a
动态链接和静态链接是编译可执行程序的一种方式
静态链接和动态链接就是看命令行参数有没有 - static
7. 软硬链接
7.1 软链接
生成: ln -s [源文件] [软链接文件]
建立一个软链接文件,指向1.txt文件
软链接文件指向普通文件,软链接文件是普通文件的快捷方式
操作软链接文件相当于操作指向的源文件,操作源文件也同样会影响软链接文件
当把1.txt源文件删除之后,再操作软链接文件1.txtln时,会发现它会自动创建一个源文件,并且与之前删除的源文件的inode节点号是一样的。所以在后面操作时,删除源文件的同时要把对应的软链接文件也一块删除。
7.2 硬链接
生成:ln [源文件] [硬链接文件]