Linux基础IO(二)

Linux基础IO(二)

缓冲区
为什么会有缓冲区

其实缓冲区的意义是节省进程进行数据 IO 的时间

怎么理解呢?我来举个例子:

孩子上大学了,学校里的水果又很贵,孩子给家里人说了,家里人知道了要给孩子每隔一段时间送点水果。下面有两个选项:

  • 1.亲自开车给孩子送
  • 2.发快递

相信大家大部分人会选择发快递吧,这样既省时间,又省事。

当然操作系统也是这样做的,它也有自己的缓冲区。当我们刷新用户缓冲区的数据时,并不是直接将数据直接刷新到磁盘或显示器上,而是先刷新到OS缓冲区,然后由操作系统将数据刷新到磁盘或者显示器。

缓冲区刷新策略
  • 无缓冲:缓冲区一出现数据,立即刷新

  • 行缓冲:缓冲区每出现一行数据就刷新一次

  • 全缓冲:缓冲区被填满后再刷新

还有两种方式强制刷新缓冲区:

  • fflush()等函数
  • 进程退出

为什么会有缓冲区刷新策略呢?

因为操作系统要求的是高效:一次写入外设等设备的时间消耗是远小于多次写入外设的效率的。其中时间消耗大部分是在等待外设就绪,例如缓冲区等待磁盘的时间就远小于缓冲区数据写入磁盘的时间,比如10秒时间内。9秒的时间是在等磁盘准备就绪,1秒是在写入数据。

操作系统可是个聪明人,它可不会傻傻的浪费自己宝贵的时间。

我们通过一段代码来加对深缓冲策略的理解:

int main()
{
    printf("aaaaaaaaaaaaaa\n");
    fputs("bbbbbbbbbbbbbb\n", stdout);

    write(1, "xxxxxxxxxxxxxx\n", 14);

    fork();
    return 0;
}

在我们直接运行程序时:

image-20230726102120541

但是当我们重定向进文件时:

image-20230726102205197

  • 第一种情况是行缓冲,我们每使用的\n都是行缓冲。
  • 第二种情况是全缓冲,因为我们把程序重定向到一个文件中,文件是全缓冲,又因为我们使用fork创建了一个子进程,而进程间互不干扰,所以都会打印一次字母a和字母b。而字母x是系统调用write,我们可以看作系统是没有缓冲区的(其实有,只是我们并不清楚规则)所以只打印一次。
系统有缓冲区吗?

用户写入数据到外设,先将数据写入系统缓冲区,再由系统刷新到外设中。

image-20230726103640596

因为操作系统是进行软硬件资源管理的软件,再加上我们之前学过的层级结构图(具体细节请看我之前写过的初识操作系统的文章),用户区的数据要刷新到具体外设必须经过操作系统,所以操作系统是肯定有自己的缓冲区的。

image-20230726103318600

文件系统

文件分为磁盘文件和内存文件,我们之前一直说的都是内存文件,下面我们来谈谈磁盘文件。

什么是inode

我们都知道文件=内容+属性,其中内容就是数据,属性就是文件名、创建日期和文件大小等。

我们输入ll命令可以查看当前路径下的文件:

image-20230726104854592

文件属性是这样的:

image-20230726110211704

我们还可以查看这些文件的inode

[wsj@VM-8-4-centos day03]$ ll -i
//或者
[wsj@VM-8-4-centos day03]$ ls -i -l

image-20230726110400049

inode到底是什么呢?

inode是一个保存元信息的结构,且因为系统中有大量的文件,为了区分每个文件,就给每个文件一个inode号,这个inode号就和我们每个人有自己的身份证号一样。

所以说inode是一个文件属性的集合。

软硬链接
软链接

我们可以通过以下命令创建一个软链接:

[---@VM-8-4-centos day03]$ ln -s mycode a_mycode

image-20230726114456471

我们通过ls -l -i可以看到软链接的文件和源文件的inode是不同的,而且文件大小也是差异很大的。

image-20230726123353422

软链接又叫做符号链接,软链接文件相对于源文件来说是一个独立的文件,它有自己的inode号,但是该文件只包含了源文件的路径名,所以软链接文件的大小要比源文件小得多。

其实软链接就类似于Windows操作系统当中的快捷方式。

所以说,运行源文件和运行快捷方式(软链接)是一样的结果。

image-20230726114855483

硬链接
[---@VM-8-4-centos day03]$ ln mycode b_mycode

image-20230726123625078

我们通过ls -l -i可以看到软=硬链接的文件和源文件的inode是相同的,而且文件大小差不多一模一样,硬链接个数也从1变成了2。

image-20230726123711402

硬连接其实就是文件的一个别名,硬链接个数就是文件别名的个数。

和软连接相比,硬链接的源文件被删除后,硬链接仍然可以执行。

image-20230726130658800

硬链接可以让多个不在或者同在一个目录下,能够修改同一个文件,且其中一个修改后,所有与其有硬链接的文件都一起修改了。

热知识

当我们创建一个普通文件时,他的硬链接是1,而我们创建一个目录文件他的硬链接是2,这是为什么?

image-20230726131129812

原因是该dir目录下必须有有两个隐藏文件...。它们分别是上级目录和当前目录,这就是我们常看别人用的cd ..的原理。(inode也是相同的)

image-20230726131349218

总结
  1. 软链接有独立的inode,硬链接没有。
  2. 软链接不能独立运行,硬链接能独立运行。
  3. 软链接相当于快捷方式,硬链接本质没有创建文件,只是对当前文件的复制加上对原来inode的映射,并写入当前目录。
文件的三个时间
  • Access:最后访问时间
  • Modify:文件最后修改时间
  • Change:属性最后修改时间
[---@VM-8-4-centos day03]$ stat day03.cc

image-20230726132046896

一般来说,Modify改变会引起Change一起变。因为修改文件内容时,文件的大小一般也会随之改变。但是Change改变却不会引起Modify改变,因为修改文件属性一般不会影响到文件内容。

使用touch命令可以将文件都更新为最新时间。

image-20230726132457483

动静态库
什么是动静态库
  • 动态库:程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。(*.so)
  • 静态库:程序在编译链接的时候把库的代码链接 (拷贝) 到可执行文件中,程序运行的时候将不再需要静态库。(*.a)
怎么理解动静态库
原理

生成一个可执行程序需要经过:预处理、编译、汇编、链接,4个阶段。

最终在汇编完成后就会*.o文件,将这样的经常使用的多个*.o文件组合起来就是一个简单的库。因为当需要使用到这个库中的哪个*.o文件,我们直接进行最后一步链接就行,省去了前3个步骤。

实际上,库都是这样做的。把常用的头文件或者函数调用汇编后组合成一个库,以供大家方便使用。

使用

我们可以通过以下命令查看可执行文件链接的库:

[---@VM-8-4-centos day03]$ ldd mycode

image-20230726192053739

我们可以通过ls命令查看libc.so.6库的情况:

[wsj@VM-8-4-centos day03]$ ls /lib64/libc.so.6 -l

image-20230726192431520

我们还可以通过以下命令来查看这个库的详细信息:

[---@VM-8-4-centos day03]$ file /lib64/libc-2.17.so

image-20230726193221821

我们可以看到这是一个动态库,而且还是一个共享的目标文件库。

我们使用的gcc/g++都是动态链接的,如果想要静态链接,我们要在编译时加上-static

我这边直接加在makefile里:

image-20230726193501575

这样我们make生成的就是静态链接的可执行程序了。

image-20230726193632679

这可比我们之前生成的动态链接的可执行程序大多了,但是它不依赖其他的库。

image-20230726193752743

我们再使用file命令,也能看出它是一个静态链接的可执行程序。

image-20230726193838320

制作一个库
前置准备

add.h

#pragma once

#include <stdio.h>

extern int add(int x, int y);

add.c

#pragma once
#include "add.h"
int add(int x, int y)
{
    return x + y;
}

sub.h

#pragma once

#include <stdio.h>

extern int sub(int x, int y);

sub.c

#pragma once
#include "sub.h"

int sub(int x, int y)
{
    return x - y;
}

main.c

#include "add.h"
#include "sub.h"

int main()
{
    int a = 10, b = 20;
    int c = add(a, b);
    int d = sub(a, b);
    printf("%d + %d = %d\n", a, b, c);
    printf("%d - %d = %d\n", a, b, d);
    return 0;
}
自制静态库

首先,我们将它们汇编为可重定向二进制目标文件:

gcc -c *.c -o *.o

image-20230726202442985

然后,我们使用以下命令将目标文件打包为静态库:

  • ar命令是gnu的归档工具,常用于打包静态库
  • -r:如果静态库文件当中的目标文件有更新,就用新的目标文件替换旧的目标文件。
  • -c:生成静态库文件。
  • -t:列出静态库中的文件。
  • -v:显示详细的信息。
[---@VM-8-4-centos day03]$ ar -rc liblocal.a add.o sub.o

image-20230726215514781

我们可以使用-v-t选项查看生成的静态库的详细信息:

[wsj@VM-8-4-centos day03]$ ar -vt liblocal.a

image-20230726215540429

最后,将头文件和生成的静态库联系起来。

[---@VM-8-4-centos day03]$ mkdir -p mymathlib/include
[---@VM-8-4-centos day03]$ mkdir -p mymathlib/lib
[---@VM-8-4-centos day03]$ cp *.h mymathlib/include/
[---@VM-8-4-centos day03]$ cp liblocal.a mymathlib/lib/

image-20230726215705688

使用自制的静态库

main.cmymathlib移动到一个新的目录下。

image-20230726204419374

使用gcc的选项-I-L生成可执行程序。

  • -I:指定头文件路径
  • -L:指定库文件路径
  • -l:指定路径下的哪一个库
[---@VM-8-4-centos day04]$ gcc -o mycode main.c -I ./mymathlib/include -L ./mymathlib/lib -l local

image-20230726215759737

然后,我们正常运行即可。

image-20230726215846754

我们也可以将我们的库拷贝到系统目录下,这样系统就可以找到我们使用的库,我们就不用指定路径了:

[---@VM-8-4-centos day04]$ sudo cp mymathlib/include/* /usr/include/
[---@VM-8-4-centos day04]$ sudo cp mymathlib/lib/liblocal.a /lib64/

image-20230726220357941

自制动态库

首先生成*.o文件。

  • -fPIC:形成位置无关码
[---@VM-8-4-centos day03]$ gcc -fPIC -c add.c sub.c

image-20230726220929255

然后,使用-shared选项打包目标文件为库。

image-20230726221200779

最后,将头文件和库联系起来。

[---@VM-8-4-centos day03]$ mkdir -p mymathlib/include
[---@VM-8-4-centos day03]$ mkdir -p mymathlib/lib
[---@VM-8-4-centos day03]$ cp *.h mymathlib/include/
[---@VM-8-4-centos day03]$ cp liblocal.so mymathlib/lib/

image-20230726221653951

image-20230726221753391

使用自制的动态库

main.cmymathlib移动到同一个目录下。

使用以下命令(和刚才使用静态库基本一样):

[wsj@VM-8-4-centos day04]$ gcc -o mycode main.c -I ./mymathlib/include -L ./mymathlib/lib -l local

image-20230726222304123

我们此刻执行后却是无法运行。

image-20230726222348403

原因是生成的可执行程序依赖的动态库没有被找到。

image-20230726222500538

解决方法:

方法1:将动态库拷贝到系统目录下。

sudo cp mymathlib/lib/liblocal.so /lib64

方法2:添加环境变量

[---@VM-8-4-centos day04]$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/wsj/bit/day04/mymathlib/lib

image-20230726223008615

方法3:配置/etc/ld.so.conf.d/

[---@VM-8-4-centos day04]$ echo /home/wsj/bit/day04/mymathlib/lib > matH.conf
[---@VM-8-4-centos day04]$ sudo cp matH.conf /etc/ld.so.conf.d

image-20230726223418618

完成任意一种解决方法后运行即可。

image-20230726223546931

感谢您的阅读,欢迎指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值