1.标准库IO接口
文件流指针(FILE *fp)
stdin(标准输入) stdout(标准输出) stderr(标准错误)
//打开文件 FILE *fopen(const char* filename,const char* mode)mode有:r、r+、w、w+、a、a+
- r:只读,打开在文件的起始位置
- r+:可读可写,打开在文件的起始位置
- w:只写,文件不存在则创建文件,文件存在则清空文件,打开在文件的起始位置
- w+:可读可写,在写入文件的时候会清空原有的内容,打开在文件的起始位置
- a:以追加的方式写入,追加到文件末尾,文件不存在则创建文件,打开文件直接显示在文件末尾
- a+:以读和追加写的方式,打开文件显示在文件的起始位置,当开始写数据时,跳转到文件末尾
//读取文件 size_t fread(void *ptr,size_t size,size_t nmemb,FILE *stream); //写入文件 size_t fwrite(const void *ptr,size_t size,size_t nemeb,FILE *stream);fread、fwrite返回值都是块个数,而非实际读取/写入的数据字节长度,因此使用时通常块大小为1,而块的个数是数据长度,这样才能返回读取/写入的数据长度
//跳转到文件的读写位置 int fseek(FILE *stream,long offset,int whence);whence有三个值:SEEK_SET(文件开头)、SEEK_CUR(当前位置)、SEEK_END(文件结尾)
offset表示以whence为基准,偏移多少字节,整数表示正向偏移,负数表示负向偏移
2.系统调用接口
常见接口:open、read、write、lseek、close
1.open
int open(const char *pathname,int flags,mode_t mode);参数信息:
- pathname:带路径文件名
- flags:选项参数
- mode:若有可能创建新文件则需要指定文件权限(例如输入权限为可读可写可执行,则需要输入0777)
- 返回值:文件的操作句柄,错误返回-1
mode_t umask(mode_t mask); //设置文件的创建权限掩码,决定了文件的默认权限
//用法:给定权限 & ~掩码
//如果有O_CREAT(创建)一定要使用mode设置权限flags(选项参数)
必选项:O_RDONLY、O_WRONLY、O_RDWR(只读、只写、可读可写三选一)
可选项:
- O_CREAT:文件不存在则创建新文件,存在则打开
- O_EXCL:文件不存在则创建新文件,存在则报错
- O_TRUNC:打开文件的同时截断文件
- O_APPEND:写入数据的时候总是追加在文件末尾
w+:O_RDWR|O_CREAT|O_TRUNC
a+:O_RDWR|O_EXCL|O_APPEND
2.write
ssize_t write(int fd,const void *buf,size_t count);参数信息:
- fd:文件描述符
- buf:要写入文件的数据缓冲区首地址
- count:要写入的数据长度
- 返回值:实际写入文件中的数据字节长度(不一定等于count),失败返回-1
3.read
ssize_t read(int fd,void *buf,size_t count);参数信息:
- fd:文件描述符
- buf:缓冲区首地址,放入读取到的数据
- count:要读取的数据长度,大小不能大于缓冲区大小
- 返回值:返回读取到的数据字节长度(不一定等于count),返回0表示读到文件末尾,失败返回-1
mode_t umask(mode_t mask); //设置文件的创建权限掩码,决定了文件的默认权限
4.lseek
off_t lseek(int fd,off_t offset,int whence);参数信息:
- fd:文件描述符
- offset:偏移量
- whence:跳转到的位置
5.close
int close(int fd);关闭文件描述符,不关闭文件描述符会导致资源泄漏
3.文件描述符(fd)
文件描述符时内核中struct file* fd arry[]数组的下标,进程可以通过这个下标找到文件的描述信息,进而操作文件
文件描述符的分配规则:最小未使用
一个程序运行起来,默认会打开三个文件,文件描述符默认从3开始
4.文件流指针和文件描述符的关系
文件流指针是库函数IO接口的操作句柄
文件描述符是系统调用IO接口的操作句柄
文件流指针是一个结构体封装了文件描述符
5.重定向的实现原理
针对文件描述符所对应的文件描述信息的重定向,此时操作文件描述符 / 文件流指针并没有发生改变,但实际操作的文件已经发生改变
常见的重定向:>、>>、<
ls 1 >> a.txt : 将标准输出重定向到a.txt
ls 2 >> &1 : 将标准错误重定向到标准输出
>> 是追加重定向
> 是清空重定向
6.文件系统==磁盘文件管理
文件系统分区
- 超级块:描述文件系统,以及inode使用情况和磁盘块使用情况
- inode_map:inode结点位图,快速查找未使用的结点位置
- data_map:磁盘块位图,快速查找未使用的磁盘块位置
- inode结点:存储文件的元信息,磁盘块位置
- data:磁盘块,存储数据,实现离散式存储
目录也是文件,inode结点和文件名称作为目录项存储在目录文件中
文件存储流程:
- 在超级块中获取文件系统信息,找到两个位图区域
- 根据位图信息,找到空闲的inode节点,以及空闲的磁盘块
- 存储数据到磁盘块中,存储文件的元信息到inode节点中
- 将文件名与inode结点号作为对应信息(目录项)保存到所在的目录中
文件数据获取流程:
- 通过文件的路径名,打开文件所在的目录文件,获取文件的目录项(inode结点)
- 通过inode结点号,找到文件的inode结点,获取文件数据存储的磁盘块号
- 在指定的磁盘块中取出数据
7.软链接文件与硬链接文件的区别
不论是软链接文件还是硬链接文件,目的都是为了通过这些文件访问到源文件
1 ln filename //创建硬链接(创建好的文件后缀名:.hard) 2 ln -s filename //创建软链接(创建好的文件后缀名:.soft) 3 ls -i //查看文件的inode结点号
- 硬链接文件跟源文件拥有相同的inode结点,类似于源文件的一个别名,通过自己的inode结点访问源文件。
- 软链接文件是一个独立的文件,有自己的inode结点(与源文件不同),通过保存源文件的路径进而访问源文件。
- 删除源文件,软链接文件失效;硬链接文件不失效,只是链接数-1(如果链接数为0,则销毁inode结点,释放空间)
- 软链接文件可以针对目录创建;硬链接不可以
- 软链接文件可以跨分区建立;硬链接不可以
8.静态库与动态库的生成与使用
静态库的生成:
1 gcc -c child.c -o child.o //生成.o文件 2 ar -cr libmychild.a child.o 3 //静态库名称:lib[filebname].a动态库的生成:
1 gcc -fPIC -c child.c -o child.o //生成.o文件 2 gcc --share -o libmychild.so child.o 3 //-fPIC的作用:产生一个未知无关代码 4 //动态库名称:lib[filebname].so使用:
- 在生成可执行程序时链接时使用:
- 将库文件放置到指定路径下(库文件的搜索路径默认/lib64)
- 设置环境变量LIBRARY_PATH,将库文件所在目录路径添加到这个环境变量的值中
- 使用gcc -L 选项,指定gcc库文件的搜索路径
- 在运行可执行程序的时候加载使用:(仅针对动态库)
- 将库文件放置到指定路径下(库文件的搜索路径默认/lib64)
- 设置环境变量LD_LIBRARY_PATH
注意:
我们在链接静态库时,并不是使用-static去指定gcc进行静态链接
因为-static的功能是在生成可执行程序的时候,所有的依赖库都是静态库,不仅仅是指定的那个库
通常在链接一个静态库的时候,都是将这个静态库放到指定路径下,直接链接这个静态库,而其他的依赖库依然会使用动态库链接