【Linux】6. 基础IO(C语言文件操作接口、系统调用文件操作接口、文件描述符、文件流指针、重定向、动态库和静态库、动态链接和静态链接、软硬链接)

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 [源文件] [硬链接文件]
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值