进程中的IO

本文详细介绍了进程中的IO操作,包括文件相关系统调用接口如fopen、fwrite、fread、fseek、fclose,以及open、write、read、lseek、close等。此外,还讲解了重定向的概念,文件描述符与文件流指针的差异,以及动态库与静态库的生成与使用。最后,讨论了文件系统的基本结构和文件存储管理,涉及超级块、inode、块位图等关键概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.文件相关系统调用接口

1.1 标准库IO接口:fopen()/fwrite()/fread()/fseek()/flcose()
(1)fopen
函数:FILE *fopen(char *filename,char *mode);
参数:
filename:要打开的文件名称
mode:r:只读/r+:读写/w:只写会清空文件原有内容/w+:写+读,会清空文件原有内容/a:写在文件末尾/a+:写在文件末尾并且可读
功能:打开一个文件
注意:r/r+/w/w+打开文件后,文件读写位置是在起始位置,注意不要覆盖写入
(2)fwrite
函数:size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp);
参数:
ptr:指向要被写入的元素数组的指针
size:要被写入的每个元素的大小,以字节为单位
nmemb:元素的个数,每个元素的大小为 size 字节
fp:FILE *fp 是声明,声明fp是指针,用来指向FILE类型的对象,*fp是指向文件结构体的指针变量,通过fp可找到存放某个文件信息的结构变量,根据这个结构变量的信息找到该文件,实施对文件的操作。fp通常被成为一个指向文件的指针。
功能:把ptr所指向的数组写入到文件中
(3)fread
函数:size_t fread( void *buffer , size_t size , size_t count , FILE *fp );
参数:
buffer:用于接收数据的内存地址,大小至少是 size*count字节
size:单个元素的大小,单位是字节
count:元素的个数,每个元素是size字节
fp:fp通常被成为一个指向文件的指针
功能:从一个文件流中读数据,读取 count个元素 ,每个元素 size字节.如果调用成功返回值大于count。如不成功,返回实际读取的元素个数,小于count.
注意:fread()/fwrite():size-块大小 count-块个数 size*count 真正要读写的数据大小,返回值是成功操作的块个数;推荐将块大小设置为1–返回值就是实际操作的数据大小与将文件读取到末尾的返回值就可以区分
(4)fseek
函数:int fseek(FILE *fp, long offset,int origin);
参数:
fp:fp通常被成为一个指向文件的指针
offset:偏移量,正数表示正向偏移,负数表示负向偏移
origin:设定从文件的哪里开始偏移,跳转文件读写位置,可能取值为:SEEK_SET: 文件开头/SEEK_CUR: 当前位置/SEEK_END: 文件结尾
功能:移动文件读写指针位置,通常文件打开后,读写位置按先后顺序
(5)fclose
函数:int fclose(FILE *fp);
参数:fp通常被成为一个指向文件的指针
功能:关闭文件
1.2 系统调用IO接口:open/write/read/lseek/close
(1)open
函数:int open(char *filename,int flag,int mode);
参数:
filename:要打开的文件名称
flag:选项参数
必选参数:O_RDONLY:只读打开/O_WRONLY:只写打卡/O_RDWR:读写打开;只能选择其一
可选参数:
O_CREAT:文件存在则打开,不存在则创建新的
O_EXCL:通常与O_CREAT同时使用,若文件不存在则创建,已经存在则会报错
O_TRUNC:打开文件的同时,清空文件原有内容
O_APPEND:写入数据的时候,总是写入文件末尾(追加写入)
r+:O_RDWR;w+:O_RDWR | O_TRUNC | O_CREAT;
a+:O_RDWR | O_CREAT | O_APPEND
mode:文件给定权限—实际权限=给定权限&掩码取反
返回值:正整数–文件描述符–后期对文件操作的操作句柄,失败返回-1
注意:1.如果open使用O_CREAT,那么一定要加上第三个创建权限参数
2.权限参数-0777,不能省略前面的0
功能:打开文件或者创建文件
(2)write
函数:ssize_t write(int fd, char data, size_t count);
参数:
fd:文件描述符—open返回的文件操作句柄
data:想要写入的数据首地址
count:写入的数据长度
返回值:>0 表示实际写入的数据长度(有可能与想要写入的长度不符);-1表示出错
功能:向文件中写入数据
(3)read
函数:ssize_t read(int fd, char buf,size_t count);
参数:
fd:文件描述符—open返回的文件操作句柄
buf:一块缓冲区的首地址,用于存储读取的数据
count:读取的数据长度
返回值:>0表示实际读取的数据长度;==0读取到文件末尾;-1出错
功能:从文件中读取数据
(4)lseek
函数:lseek(int fd, off_t offset, int whence);
参数:
fd:文件描述符—open返回的文件操作句柄
offset:偏移量,正数表示正向偏移,负数表示负向偏移
whence:设定从文件的哪里开始偏移,跳转文件读写位置,可能取值为:SEEK_SET: 文件开头/SEEK_CUR: 当前位置/SEEK_END: 文件结尾
功能:移动文件读写指针位置,通常文件打开后,读写位置按先后顺序
返回值:调用成功时则返回目前的读写位置,也就是距离文件开头多少个字节。若有错误则返回-1
功能:移动文件读写指针位置,通常文件打开后,读写位置按先后顺序
(5)close
函数:close(int fd);
参数:fd:文件描述符—open返回的文件操作句柄
功能:关闭文件
上面的 fope/fclose/fread/fwrite 都是C标准库当中的函数,我们称之为库函数(libc)。 而, open/close/read/write/lseek 都属于系统提供的接口,称之为系统调用接口。库函数封装了系统调用接口。

2. 重定向

2.1 文件描述符与文件流指针
文件描述符:实际上就是内核中一个文件描述信息结构体数组的下标,进程通过pcb找到flies_struct,进而找到数组fd_arry,在通过描述符找到具体的文件描述信息。
Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2。0,1,2对应的物理设备一般是:键盘,显示器,显示器
文件流指针:是一个结构体,并且这个结构体中封装了一个成员就是文件描述符
文件描述符是系统调用的操作句柄,文件流指针是库函数的操作句柄
2.2 用户态和内核态
用户态:若当前进程运行的程序是程序员自己写的代码,则进程运行用户态
内核态:若当前进程运行的程序是系统调用/操作系统实现的功能,则进程运行在内核态
用户态缓冲区—每一个FILE结构体中自带的缓冲区
2.3 重定向的实现
要操作的stdout/文件描述符都没有变,但是通过改变这个文件描述符对应下标描述信息,进而实现改变当前所操作的文件的目的
在这里插入图片描述
系统调用重定向:int dup2(int oldfd,int newfd);
功能:将newfd这个描述符下表对应的文件描述信息也指向oldfd所指向文件,操作完成之后,oldfd和newfd两个描述符操作的都是oidfd原本所操作的文件。
重定向符号
(1)>> 追加 (2)> 清空
命令操作:ls -l -a | >>a.txt
ls -l -a 将浏览结果使用printf写入到标准输出 stdout-> 1

3.动态库与静态库的生成与使用

动态库:程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。
静态库:程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静 态库。
生成动态库:1.gcc -fPIC -c child.c -o child.o 2.gcc -shared child.o -o libmychild.so
-fPIC:产生与位置无关代码 -c:只进行与处理,编译,汇编,但是不链接
-shared:生成动态块而不是可执行程序
库名规则:libxxx.so
生成静态库:1.gcc -c child.c -o child.o 2.ar -cr libmychild.a child.o
ar:生成静态库的命令 -c:创建 -r:模块替换
库名规则:libxxx.a
使用:
(1)生成可执行程旭的时候链接使用:
a.将库文件放到指定的路径下:/lib64 /usr/lib64
b.设置环境变量:export LIBRARY_PATH=${LIBRARY_PATH};../
c.设置gcc选项:gcc main.c -o main -L./-lmychild(gcc -L选项,用于指定库的链接搜索路径)
(2)运行可执行程序的时候加载使用:(只针对动态库生成的可执行程序)
a.将库文件放到指定的路径下:/lib64 /usr/lib64
b.设置环境变量:export LD_LIBRARY_PATH=${LD_LIBRARY_PATH};../

4.文件系统

4.1 文件系统:磁盘中的文件存储管理
以ext2文件系统为例:(图中给出的是主要部分)
在这里插入图片描述
Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成
超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量, 未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的 时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了
GDT,Group Descriptor Table:块组描述符,描述块组属性信息
块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用 inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用
i节点表:存放文件属性如文件大小,所有者,最近修改时间等
数据区:存放文件内容
4.2 存储一个文件流程:
1.通过超级块获取databitmap的地址,通过databitmap获取到空闲的磁盘块号,将文件数据写入指定的磁盘块
2.通过超级块获取到inodebitmap的地址,通过inodebitmap获取一个空闲的inode节点,将文件元信息写入其中
3.将文件的文件名以及inode节点号的对应信息(目录项),写入到这个文件所在的目录
4.3 获取一个文件数据的流程:
1.通过文件名,在所在目录中找到自己的目录项(包括当前文件的inode节点)
2.通过超级块找到inode-table区域,通过inode节点号找到相应的inode节点
3.通过inode节点,就能找到文件数据存储的磁盘块号
4.找到磁盘块,读取数据
4.4 软链接文件和硬链接文件
软链接文件的创建:ln -s sfile dfine
硬链接文件的创建:ls sfine dfile
软链接与硬连接的区别:
a.软链接文件:一个独立的文件,文件数据中保存的是源文件的路径,通过路径访问源文件
b.硬链接文件:跟源文件没有什么区别,与源文件共用同一个inode节点,通过访问同一个inode实现文件数据的获取
c.软链接就是一种类似win下边快捷方式的文件,而硬链接就是一个文件别名
d.删除源文件,则软链接文件失效,而硬链接文件依然可以访问文件数据
e.软链接可以跨分区建立,也可以对目录创建,硬链接不可以

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值