IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Linux: 基础IO 重定向 静态库与动态库 -> 正文阅读

[系统运维]Linux: 基础IO 重定向 静态库与动态库

基础IO:

库函数IO接口:

FILE * fopen(char *pathname,char*mode);
pathname:文件路径名 , mode:文件的打开方式 . 返回值:打开文件成功则返回一个FILE*文件流指针作为文件的操作句柄,失败返回NULL

r 只读方式打开文件,文件必须存在? ? ? r+ 读写方式打开文件,文件必须存在

w 只写方式打开文件,文件不存在则自动创建,存在则清空内容? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

w+ 读写方式打开文件,文件不存在则自动创建,存在则清空内容? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

?a 追加写方式打开文件,文件不存在则自动创建,存在则写入数据总是写入文件末尾? ? ? ? ? ? ? ? ?

a+? 读+追加写方式打开文件,文件不存在则自动创建,存在则写入数据总是写入文件末尾? ? ? ? ? ?

b二进制方式打开文件.

在系统调用IO接口中并不区分文本和二进制数据,统一按照二进制进行处理,
但是库函数不一样,区分文本和二进制,默认文本操作,但是有的文本一个字符占据多个字节
例如:一个文件中有10个字节数据,但是读取的时候读取完毕后读取大小是9,这个9表示的不是9个字节而是9个字符


size_t fwite(const void* data,size_t bsize,size_t nmem,FILE* fp);
data:要写入文件的数据所在空间首地址;

bsize:要写入的块大小;nmem:要写入的块个数;bsize*nmem 就是实际要写入文件的大小? ? ? ? ? ? ?

fp: fopen返回的文件流指针,标识要操作哪一个文件

返回值:返回实际完整操作的块个数? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

注意:r+/w/w+方式文件打开之后,文件的默认读写位置在文件起始,如果文件中本身就有数据,就会覆盖,并且读写位置会随着数据的写入向后偏移;a/a+方式打开文件之后,读默认是从文件起始读的,但是如果写会使读写位置跳转到文件末尾,将数据追加到未尾
?

size_t fread(void *buf,size_t bsize,size_t nmem,FILE*fp)
buf:一块空间的首地址,用于存放从文件中读取的数据

bsize:块大小;nmem:块个数; bsize*nmem 就是实际要读取的数据大小?,

fp:fopen返回的文件流指针
返回值:成功返回实际操作的完整块个数,出错了返回0

注意:这个函数返回值存在多义性,返回0的时候无法直接确定是出错还是读到文件末尾了
例如一个文件100个字节,我现在读取数据块大小200,块个数1,因为没有读取完整的一块,并且读取到了文件末尾因此返回了—个0。这时候这个0就无法确定是出错了还是正常的。
因此,建议fread读取数据的时候,块大小设置为1,想要读取的长度设置为块个数,这样返回值就能告诉我们读取了多少个字节的数据


int fseek(FILE *fp,int offset,int whence);

改变文件读写位置,跳转到哪里就从哪里开始读写

fp:文件流指针; offset:偏移量;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

whence:偏移起始位置SEEK_SET-起始/SEEK_CUR-当前/SEEK_END-末尾返回值:成功返回0;失败返回-1

比如我们使用a+追加写入文件后想读取文件信息这时候我们是读不到东西的,因为读写位置已经到文件末尾了,这时我们就需要先来一个 fseek(fp,0,SEEK_SET) 使读写位置从新回到开头,再读取? ? ? ?
int fclose(FILE*fp);

每次文件使用结束关闭文件释放资源,否则造成资源泄漏
?

系统调用IO接口:

int open(char *pathname, int flag,mode_t mode);
pathname:要打开的文件路径名

flag:文件打开标志--决定了文件的打开方式? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

返回值:成功返回一个非负整数-文件描述符-是文件的操作句柄 这个下面会讲到; 失败返回-1;?

mode:文件的权限,通常采用八进制数字设定0777或0664,如果使用了O_CREAT就一定要有第三个参数,第一个数字0是不可少的.? 文件的创建权限是受到到umask掩码影响的。实际文件得到的权限mode&(~umask).

mode_t umask(mode_t mask);通常在程序起始阶段调用umask(0)将当前进程的创建掩码设置为0,这样文件权限就和open的mode参数一样了,零取反得777与上mode得mode自身.

必选标志: O_RDONLY-只读/O_WRONLY-只写/O_RDWR-读写,只能选择其中一个,不能同时使用
可选标志: O_APPEND-追加写│O_CREAT-文件不存在则创建|O_TRUNC-文件存在则截断为0|O_EXCL-文件存在则报错

比如fopen中w+: 读写+创建+截断O_RDWR |O_CREAT |O_TRUNC
? ? ? ?fopen中a+: 读+追加写,创建O_RDWR |O_APPEND |O_CREAT


ssize_t read(int fd,void *buf, int len);
fd : open返回的文件描述符-操作句柄-表示操作哪个文件? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

buf:一块空间地址,用于存放读取到的数据

len:要读取的数据长度

返回值:成功返回实际读取到的数据长度;失败返回-1;

ssize_t write(int fd, void *data, int len)
fd:文件描述符-操作句柄; data:要写入文件的数据的空间首地址; len:想要写入文件的数据长度返回追:成功返回实际写入文件的数据长度;失败返回-1;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

off_t lseek(int fd,off_t offset,int whence);
fd:文件描述符; offset:偏移量; whence:偏移起始位置SEEK_SET / SEEK_CUR / SEEK_END
返回值:成功返回跳转后的位置相对于文件起始位置的长度(额外用法:跳转到文件末尾则返回文件长度)﹔失败返回-1int

和fseek一样:比如我们使用a+追加写入文件后想读取文件信息这时候我们是读不到东西的,因为读写位置已经到文件末尾了,这时我们就需要先来一个 lseek(fd,0,SEEK_SET) 使读写位置从新回到开头,再读取

???????

close(int fd);关闭文件释放资源
?


文件描述符与文件流指针:

文件描述符就是open的返回值fd? ,? 文件流指针就是fopen的返回值fp

系统调用接口封装在库函数中,所以文件描述符也就封装在文件流指针中了.

通过下面老师画的图理解文件描述符:

???

文件描述符本质上就是内核中,进程打开的文件IO信息指针数组的一个下标
当我们通过描述符操作文件的时候,在pcb中找到files _struct结构体指针,进而找到结构体,找到结构体中的数组,以描述符作为下标获取到数组中存放的文件描述信息的地址,通过描述信息操作文件

为什么第一个打开的文件的文件描述符是3呢?因为一个进程运行之后默认会打开三个文件:stdin标准输入,stdout标准输出,stderr标准错误?. 分别为键盘,显示器,显示器,? 他们的文件描述信息分别占据了0,1,2数组下标的位置.所以0,1,2号文件描述符分别指向键盘,显示器,显示器.?再打开文件会优先放在数组下标最小的位置, 所以就成3了.?

再比如下面可以通过先close(1)断开1号文件描述符指向显示器,? 再打开一个文件,? 之后这个文件就变成1号文件描述符指向的文件,? 之后操作的东西如果原本输出到显示器的就会写入到文件里,? 而不再输出到显示器了,这也是重定向的原理:改变了文件描述符对应的文件描述信息, 就改变了操作了的文件,但文件描述符没有变.

重定向:

1.如下图, 1号文件描述符是标准输出,所以write(1,str, )写入的str只会显示在屏幕(显示器)上,不会写进某个文件.

2.和上面所说,关闭1号后再打开文件会优先匹配最小的数组下标所以打开的test.txt文件的文件描述符就成了1.再write(1, ,)就会写进重定向的文件中而不会再显示在屏幕上

?

?3.重定向的接口:dup2(int fd1,int fd2),使文件描述符fd2对应的文件描述信息改为fd1对应的文件描述信息,成功则关闭fd2原先指向的文件描述信息,这时fd1和fd2都操作fd1对应的文件

files_struct结构体中的_fileno成员就是文件描述符,? 所以也可以用下面这句stdout->_fileno=fd改变标准输出的文件描述符1 改为想给的fd.(屏幕显示器的文件流指针就是stdout).

4.文件流指针指向的结构体中不止封装有有文件描述符,还有缓冲区.

所以fwrite是有文件缓冲区的,而write就没有了.所以下面的代码运行会直接打印write,程序退出前刷新文件缓冲区才打印出缓冲区里的hello bit和fwrite

这也是系统调用接口_exit()没有缓冲区,库函数exit()有的原因.不了解缓冲区的朋友可以去看我前面写的linux进程概念与控制中文字概念中有详细介绍

标准输出重定向:

>>是我们的标准输出重定向符号,一个 '>' 是清空重定向就像O_TRUNC,? 两个''>>''是追加重定向就像O_APPEND.

比如? ls >> test.txt? 就是将原本打印出来到屏幕上的当前目录下的文件信息 不再打印出来 而是重定向到指定的test.txt中.? 下面我们通过minishell理解标准输出重定向的过程!

思路是分析接收到键盘指令的cmd, 若含 '>' 符号就使该符号位置设为'\0',? '\0' 前面的字符串就是对应的指令.计算 '>' 的个数使后面在程序替换执行该执行的指令前决定重定向是追加还是清空, 设置为'\0'再往后看, >>后第一个非空格非'\0'的字符就是重定向指定文件的文件名首地址设置为filename,则位置到'\0'之间的字符串就是要写入信息的文件名.

动态库与静态库生成与使用:

库的命名:一定为lib作前缀+中间自定义库名称+.os后缀(动态库)/.a后缀(静态库)

库:将很多写好的功能性代码打包成的一个文件(库中不能有main函数)

前面写的linux常用指令和常用工具gcc介绍部分中写有静态链接和动态链接的区别.

生成:嘿嘿?

使用:

1. 使用-l来指定要链接的库名称(前提是库文件需要放到指定路径下:/usr/lib64 )? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
2.如果库文件不在/usr/llib64底下也不希望把库文件拷贝过去, 也可以通过改变环境变量指令:?export LIBRARY_PATH=$(LIBRARY_PATH):./??设置环境变量,将库文件所在目录加入到环境变量路径中,? 再使用? gcc main.c -o main -lchild ? 生成链接了child库的可执行程序main

运行可执行程序的时候使用:? ?(仅限于动态库--因为只有链接动态库,运行程序的时候才需要加载)
静态库使用时是把库中用到的代码直接放入到可执行程序,动态库使用是只记录函数符号信息,因此运行时依赖??export LD_LIBRARY_PATH=${LD_LIBRARY_PATH):./??设置环境变量中的库文件加载路径.这两句export必须配对一起使用,不然没有下面这个export的话./main执行时程序没法执行

3.(常用)使用gcc -L选项指定库文件的所在路径(常用于链接静态库--因为静态库没有依赖,运行时不需要加载)??gcc main.c -o main -L./ -lchild? 使用main.c和自定义的库名称生成一个main可执行程序

要是没有-L./指定库文件所在路径为./(当前目录下)就需要把库文件拷贝到/usr/lib64底下

要是./下有同名的child动态静态库文件(libchild.so,libchild.a)默认链接动态库.

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-11-11 13:06:47  更:2021-11-11 13:08:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 23:50:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码