Linux基础IO-2

FILE

C语言中使用open函数,返回的是一个FILE*,fread,fwrite都是通过FILE*来完成对文件的输入输出,在上一篇中我们知道了,系统通过文件描述符来定位到文件的,所以FILE里面必定封装了fd。


 #include <stdio.h>
 #include <string.h>
 
int main()
 {
    const char *msg0="hello printf\n";
    const char *msg1="hello fwrite\n";
    const char *msg2="hello write\n";
 
    printf("%s", msg0);
    fwrite(msg1, strlen(msg0), 1, stdout);
    write(1, msg2, strlen(msg2));
 
    fork();
 
    return 0;

在这段代码中我们分别使用printf,fwrite,write来进行输出,其结果都是打印到屏幕上

hello printf
hello fwrite
hello write

就是这样,但是当我们进行重定向,将一个文件的文件描述符重定向到标准输出中时会发现,fwrite和printf与write有不同的结果,属于C函数库的fwrite和printf会向文件中写入两次。但是打印到屏幕上就只打印一次。

这里就要在fork和重定向中入手,fork创建子进程时在不修改数据时会共用一份代码,但是一旦数据出现修改等操作时会发生写时拷贝。那么数据就会有两份,而C语言库的输出函数是有缓冲区的,一般向文件写入的是全缓冲模式,即当我们执行到fork时,数据还在函数的缓冲区中,当进程结束,统一由操作系统进行刷新缓冲区,导致父子进程各向文件写入一份数据。而系统调用的write只有一份,说明其并没有所谓的缓冲区。

文件系统-ext2

当我们使用ls -l 查看文件时除了文件名还有文件元数据,从左到右分别是

模式:d代表目录文件,-代表一般文件,后面就是每三个字符代表所有者,所属组和其他人的权限

硬链接数量

文件所有者

文件大小:指此文件的大小,目录文件不包含内容大小

最后修改时间

文件名

这里的都是目录文件,目录文件用于存放文件信息和文件索引的

除了ls -l 还可以使用stat命令查看文件信息

四个时间分别是:最后访问时间,最后修改时间,属性的最后修改时间,创建时间

文件和数据都是存储在磁盘中的,磁盘是典型的块文件设备,硬盘被划分成一个个的block区域,每个block都有其对应的编号,block的大小由格式化时确定的,并且不可更改。ext2支持1024B,2048B和4096B

Block Group:ext2文件系统根据分区的大小将磁盘划分为多个block group,如windows中的ABCD盘,每个分区内部都由相同的结构组成

boot block是启动块固定1KB并不是ext2文件系统的标准,而是pc标准,主要存放磁盘分区信息和启动信息,包括引导器,引导程序,计算机启动时bios从启动块中读取引导代码,将操作系统内核加载到内存中

分区表信息:记录分区的起始位置,大小和类型信息

磁盘的主分区表在MRB-磁盘的第一个扇区(1个扇区512字节磁盘规定,也有一些特殊的可以做到根据磁盘的结构进行扇区大小的变动,这里暂不考虑)

根据上面两张图,我们试着还原一下文件创建过程。

我们touch一个文件,系统会在indeo表中寻找一个空的inode,将文件信息如文件大小,所有者,权限,时间存入。当我们在文件中写入数据,系统会根据数据大小在block bitmaps中找到空闲的内存块,将数据存入,在inode中存入数据存储块的地址,这里指的是相对地址,如在100,200,300中找到空闲的数据块,其代表着是从整个data blocks起始位置开始,向后第101块内存块。

目录文件也是相同原理的,但是在文件的属性上是d所以操作系统对待目录文件会将其当作文件的索引文件,就是一种映射关系,将文件名字与对应inode进行映射。

软硬连接

在系统中是通过inode找到对应文件,文件名与inode之间只是映射关系,所以是可以多个文件名映射同一个inode的

在linux中可以通过如下代码进行硬链接

touch abc
ln abc def

通过 ls -1i 查看两个两个文件的大小的相同的,而且其硬链接数都是2

我们删除abc文件

此时链接数变成了1,

当我们将def也删除,硬连接数变成0,系统就将此对应的磁盘空间释放。

软连接是一种索引,可以通过软链接文件找到其本身的文件

ln -s ./def def.h
ln -s /home/liujj/liujj/1.testPipe/def def.s

新建的软连接文件是保存了链接的文件的路径

当我们删除了源文件,这个软连接就没有用了

动静态库

在Linux中静态库文件以.a结尾,动态库文件以.so结尾

程序的运行大都需要链接外部的库文件,如C需要<stdio.h>,C++需要<iostream>

在执行程序时,若程序的动态链接,操作系统将对应文件加载到内存中供程序调用使用,若是,静态库在编译文件时就会将其拷贝到文件中,因此,静态编译的可执行程序会比动态链接的程序大许多,而且动态库只需要加载一份代码到内存中就可供多个程序使用,节省了磁盘和内存的空间,因此,大部分的程序都是运用的动态链接方式。

库生成

linux gcc编译器有三个阶段

1.预处理阶段

gcc -E  filename.c -o filename.i

编译出来的文件会停留在完成预处理指令的阶段,处理以#开头的预处理指令

展开宏定义,包含头文件,条件编译,删除注释,处理后文件以.i结尾

2.编译阶段

gcc -S filename.i -o filename.s

经过编译阶段的文件会停留在完成预处理和编译的阶段

将代码转化成汇编代码,文件以.s结尾

3.汇编

gcc -c filename.s -o filename.o

将汇编代码转换成机器码,生成可重定位的目标文件以.o结尾。

最后编译器会将目标文件和库文件链接成可执行文件并没有中间文件,出来的就是可执行程序了。

生成静态库

我们创建四个文件,add.c  add.h  mod.c  mod.h里面分别包含了函数加法和除法的实现和定义。

我们需要先将.c文件使用-c生成第三阶段文件即机器码文件

ar -rc libmymath.a add.o mod.o

ar是gnu的归档工具,rc表示:replace and create生成静态库

编译包含这两个头文件的程序时加上库的路径的名字即可

gcc main.c -o main -L ./ -lmymath

库名全称时libmymath.a但是真正库名是去掉前缀lib和后缀的。

生成动态库

还是四个文件为例

gcc -fPIC -c sub.c add.c

使用选项-fPIC产生位置无关码,会自动生成.o文件

gcc -shared -o libmymath.so add.o mod.o

因为动态库使用很多,gcc本身就有生成动态库的功能

使用方式和静态一样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值