包括以下部分的总结:
- 标准库IO接口与系统调用IO接口
- 文件流指针与文件描述符
- 系统调用与库函数的关系
- 文件系统中的inode节点
- 软链接与硬连接
- 动态库与静态库
C标准库IO接口(库函数)
man 手册 ----3
fopen,fwrite,fread,fseek,fclose
FILE *fopen(char *filename,char *mode)
mode:r 只读, r+ 读写;w 只写, w+读写;a 追加只写 数据总是写入文件尾部,a+追加读写;b对文件数据进行二进制操作
size_t fwrite(char* data,size_t block_size,size_t block_num,FILE *fp)
data 要向文件中写入的数据
block_size 块大小
block_num 块个数
fp fopen返回的文件操作句柄-文件流指针
返回值 实际操作的块个数,失败返回0;
size_t fread(char* buf,size_t block_size,size_t block_num,FILE *fp)
buf 读取的数据存放在内存的指针
返回值 实际操作的块个数,失败返回0;
文件读写位置指针:指向文件当前即将写入或者读取的数据的位置(相对于起始位置的偏移量)
- r,r+,w,w+打开文件,读写位置指针默认指向文件的起始地址
int fseek(FILE *fp,int offset,int whence)
fp 文件流指针
offset 相对 whence的偏移量
whence SEEK_SET–起始位置 SEEK_CUR–当前位置 SEEK_END–末尾位置
成功返回0 失败返回-1
系统调用IO接口
man 手册 ----2
open write read lseek close
int open(char* filename,int flag,int mode)
filename 文件名 mode 打开方式
flag:必选 O_RDONLY/ O_WRONLY/ O_RDWR
可选项 O_CREAT 文件不存在则创建; O_EXCL 与O_CREAT同时使用,若文件存在则open报错返回;O_APPEND 以追加写入;O_TRUNC 打开同时清空文件
返回值: 成功返回文件描述符 失败返回-1
ssize_t write(int fd,char *data,int count)
fd 文件描述符; data 写入文件的数据的首地址 ;count 要写入的长度
返回值:实际写入的文件的字节长度,失败返回-1;
ssize_t read(int fd,char *buf,size_t count)
fd 文件描述符
buf 缓冲区首地址,读到的数据就放在这里
count 要读取的数据长度
返回值:成功返回数据长度 失败返回-1
off_t lseek(int fd, off_t offset,int whence)
whence SEEK_SET起始 SEEK_CUR当前 SEEK_END结尾
返回值 跳转位置相对于文件起始位置的偏移量(可跳转到文件末尾,求文件总长度)
int close (int fd)
注 linux文件都以2进制操作
mode_t umask(mode_t mask)
创建权限掩码 —0
文件描述符与文件流指针
文件描述符
直观理解:是一个非负整数,是系统调用IO的操作句柄,通过这个数字可以让系统知道要操作那个文件。
本质:就是内核中文件描述信息数组的下标,
1.进程打开一个文件,就会创建一个struct file 结构体来描述这个文件信息
2.将这个结构体存储空间的地址,放到进程的文件描述信息数组中
3.将数组放置描述信息的这个节点的下标作为文件描述符返回给用户
文件流指针与文件描述符的关系:
文件流指针:fopen返回FILE* fp。是标准库IO接口的操作句柄
文件描述符:open返回 int fd,是系统调用接口的操作句柄
库函数和系统调用接口的关系:
系统调用接口经过封装后----> 得到库函数
系统调用接口是操作系统向上提供的访问内核的接口
重定向实现:
/ >清空重定向,将现有数据写入指定文件之前,先进行清空
/ >>追加重定向 直接追加到指定文件原有内容之后
标准输入 0
标准输出 1
标准错误 2
栗子:>/dev/null 2>&1 将标准输出和标准错误都重定向到指定的文件
实现原理:
改变一个描述符下标节点 中的文件描述信息。
int dup2(int oldfd,int newfd)
改变newfd的文件指向
让newfd这个文件描述符也记录oldfd的文件描述信息,使得oldfd和newfd都可以访问到oldfd
ls>> a.txt 标准输出重定向应该如何实现?
1.在ls进程中打开a.txt文件
2.使用dup2进行标准输出重定向 让1指向 a.txt dup2(a.txt-fd,1)
动态库与静态库
库文件:一堆二进制代码实现的集合文件
库的生成:将一大堆代码实现打包生成一个库文件
c源码—>二进制代码---->多个二进制代码进行打包---->库文件
静态库 :
- (.a)后缀名结尾,程序在编译链接时把库的代码链接到可执行文件中,这种 方式可执行文件中拥有所有需要的代码实现,自己就可以单独运行。因此程序运行的时候就不需要库文件了
- gcc -c child.c -o child.o 生成二进制代码 ar -cr libchild.a child.o使用ar打包静态库
动态库:
- (.so)程序在运行时才去连接动态库的代码, 只是将动态库的函数信息表记录到可执行程序中,这种方式生成的可执行程序中没有具体代码,所以运行时需要依赖库文件
- lib 前缀 .so 后缀 gcc -fPIC -c child.c -o child.o 先将源码编译成二进制代码 –fPIC生成位置无关代码 gcc -shared child.o libchild.so –shared 告诉编译器生成的是库文件而不是可执行文件
使用:生成可执行程序时链接使用,运行可执行程序时的加载使用(仅针对动态库)
生成可执行程序时链接使用
生成可执行程序使用的是gcc编辑器,在生成可执行程序的时候,使用-l选项指定要链接的库文件名称 如果库文件名称为:libmytest.so libmychild.a
gcc main.c -o main -lmychild
gcc编译器在生成可执行程序时,加入链接了库文件,就会默认到指定路径下去找一些库文件
将库文件放到默认指定的路径下 /lib64(拷贝过去)
环境变量LIBRARY_PATH 保存默认查找路径,将库文件所在路径添加到环境变量中 export LIBRARY_PATH = ${LIBRARY_PATH}:.
使用gcc编译选项 -L指定库文件所在路径 gcc main.c -o main -lchild -L./
-L 库路径 -l库名称(去掉lib和so)
运行可执行程序时的加载使用
程序运行时,会自动根据程序依赖的动态库信息,去将指定的动态库加载到内存
加载时,会默认去指定的路径下寻找库文件
将库文件放到指定路径下 /lib64
环境变量LD_LIBRARY_PATH 保存加载路径
文件系统
磁盘上管理文件存取的系统
一个磁盘上有多个分区,每个分区都有一个文件系统来管理这个分区的文件存储
文件存储流程:
- 在超级块(存放文件系统本身的结构信息)中获取文件系统信息(各个区域起始位置),找到两个位图区域(inode位图和data位图)
- 根据位图信息,找到空闲的inode节点,以及空闲的数据库
- 存储数据到数据块中,存储文件的元信息到inode节点中
- 将文件名与inode节点号,作为对应信息(目录项)保存在所在目录的文件中
文件数据获取流程:
1.通过文件的路径名,打开文件所在的目录文件,获取到文件的目录项(得到文件的inode节点号)
2.通过inode节点号,找到文件的inode节点,获取到文件数据存储的磁盘块号
3.在指定的磁盘块中取出数据
软链接与硬链接
都是针对源文件而创建出的,访问这两种文件就相当于访问源文件
本质区别:
软链接文件是一个独立的文件,有自己的inode节点,通过保存的原文件路径访问源文件
ln -s test.txt test.soft
硬链接文件,与源文件没有什么区别,都是一个文件的目录项,拥有相同的inode节点号,通过自己的inode节点号访问文件数据
ln test.txt test.hard
特点:
删除源文件,软链接文件会失效,但硬链接文件不受影响
软链接文件可以跨分区建立,但是硬链接文件不可以
软链接文件可以对目录建立,但是硬链接文件不可以