【Linux】Linux Progress Pulse-进度条

发布于:2025-03-10 ⋅ 阅读:(15) ⋅ 点赞:(0)

 > 🍃 本系列为Linux的内容,如果感兴趣,欢迎订阅🚩

> 🎊个人主页:【小编的个人主页

>小编将在这里分享学习Linux的心路历程✨和知识分享🔍

>如果本篇文章有问题,还请多多包涵!🙏
>  🎀   🎉欢迎大家点赞👍收藏⭐文章

> ✌️ 🤞 🤟 🤘 🤙 👈 👉 👆 🖕 👇 ☝️ 👍


目录

 🐼前言 

 🐼回车pk换行,缓存区刷新机制

  🐼小demo

 🐼进度条编写


 🐼前言 

我们将使用LInux中基础指令,使用工具vim编写一个进度条程序。通过自已编写的Makefile,使用指令make形成可执行程序,使用指令make clean清理文件

进度条效果演示:

进度条效果演示

 🐼回车pk换行,缓存区刷新机制

 回车换行是一个概念吗?

答案显然不是,回车是指光标回到这一行的初始位置(\r就是回车的转义字符),换行是直接切换到下一行,而不回到这一行的初始位置,而我们平时C语言中使用的"\n"默认是回车+换行

那这有什么用呢?我们来观察一个现象:

首先我们创建一个code.c文件来观察,其内容是:

形成可执行程序

运行结果,我们发现,hello world先被打印到显示屏上,然后过了一秒,程序完成,符合我们的预期。

我们这次不加"\n"试试:

现象:发现,屏幕中先过了一秒,然后最后显示出来hello world

那我们这次只加回车"\r"试试:

现象:发现hello world竟然被吞掉了,什么都不打印,这是为什么????hello world 去哪了??

其实在睡眠期间,hello world在缓存区中,而"\n"作为一种刷新机制,可以直接刷新到显示屏文件中,所以我们看到了hello world。第二种,在程序结束后,将缓存区中的内容拷贝到显示屏文件中,所以我们也能看到,第三种,加了"\r"回车,我们看不到的原因是因为,光标回到这一行的开始位置,程序结束,将光标前的内容刷新,没有内容,所以什么都没有。

总结一下刷新机制:

1:如果\n或者\r\n,会使\n之前的内容,全部刷新到显示器上

2:程序结束,历史数据,会被刷新到显示屏上

那对于第三种情况,如果我们想强行刷新到显示屏上可以使用fflush函数进行刷新(即将缓存区的内容刷新到显示屏中):

修改完再打印一下code.c

此时即是回车,也将内容刷新到显示屏上。

  🐼小demo

那既然有了以上理论,我们可以实现一个简易版的计时器,回车到起始位置,进行刷新覆盖.

#include<stdio.h>
#include<unistd.h>

int main()
{
    int n = 10;
    while(n)
    {
        printf("%-2d\r",n);
        fflush(stdout);
        n--;
        sleep(1);
    }
    printf("\n");
    return 0;
}

每次打印完,回车到起始位置,将内容刷新到显示屏上,光标又回到了行开始位置。让我们有了一种计时器倒计时的感觉。回车的目的就是将光标重新回到起始位置。

 🐼进度条编写

 下面我们实现一个进度条,目标有三个:

1:能不断加载进度条

2:能显示百分比

3:加载图标能不能转动,表示加载中~

下面我们先根据以上要求实现一个简易版:

我们通过"process.h","process.c","main.c"三个文件进行实现:

让我们的进度条先跑起来:

"process.c"逻辑

#include"process.h"
#define LENGTH 101
#define LABLE '#'

void process()
{
    //定义缓存区
    static char bar[LENGTH];
    memset(bar,0,sizeof(bar));
    //定义光标
    const static char* str = "/|\\-";
    int len = strlen(str);
    int cnt = 0;
    while(cnt<LENGTH)
    {
        printf("[%-100s][%d%%][%c]\r",bar,cnt,str[cnt%len]);
        fflush(stdout);
        bar[cnt++] = LABLE;
        usleep(20000);
    }
    printf("\n");
}

我们通过让cnt不断增长,我们默认进度条的长度最多为100字'#',直到填充满,每次填充,我们都进行刷新,并让光标回到初始位置,为下一次刷新做准备,加载图标通过通过取模运算每次更新。

verson1进度条演示:

verson1

可是,这样,是不符合实际情况的。原因:

我们的下载速度都是与下载包大小和网速有关的,所以进度条增加速度我们需要关心。

即进度条不能直接更新完,要根据具体进度进行刷新

我们更新一下下载逻辑:

通过下载安装包和下载速度实时更新,下载一次每次都刷新进度条,只要没下载完,就一直下载。

"main.c"

#include"process.h"
//直接替换
#define  TOTAL 1024.0
#define  SPEED 1.0

//检查对比一次,并加几组,看看下载速度和网速
void DownLoad(double total,double speed)
{
    double current = 0;
    while(current<=total)
    {
        FlushProcess(current,total);
        usleep(2200);
        current+=speed;
    }
}
int main()
{
    printf("下载中\n");
    DownLoad(TOTAL,SPEED);
    DownLoad(1024.0,1.0);
    DownLoad(512.0,2.0);
    DownLoad(800.0,4.0);
    DownLoad(2000.0,2.0);
    DownLoad(10240.0,10.0);
    printf("下载完成>^o<^\n");
    return 0 ;
}

"process.c"

#include"process.h"
#define LENGTH 101
#define LABLE '#'

void FlushProcess(double current,double target)
{
    //更新出当前进度
    double rate = (current/target)*100.0;//200-1000
    //整数个进度递增,刷新一个#
    int cnt = (int)rate;
    //定义光标
    const static char* sysb = "/|\\-";
    int len = strlen(sysb);
    static int index = 0;
    //缓存区
    static char bar[LENGTH];
    memset(bar,0,sizeof(bar));
    for(int i=0;i<cnt;i++)
    {
        bar[i] = LABLE;
    }

    printf("[%-100s][%.1lf%%][%c]\r",bar,rate,sysb[index++]);
    fflush(stdout);
    index%=len;
    
    if(rate>=100.0) printf("\n");
    fflush(stdout);
}

"process.h"

#include<stdio.h>
#include<unistd.h>
#include<string.h>
void FlushProcess(double current,double target);

最后,看一下我们做出来的效果:

verson2:

   感谢你耐心地阅读到这里,你的支持是我不断前行的最大动力。如果你觉得这篇文章对你有所启发,哪怕只是一点点,那就请不吝点赞👍,收藏⭐️,关注🚩吧!你的每一个点赞都是对我最大的鼓励,每一次收藏都是对我努力的认可,每一次关注都是对我持续创作的鞭策。希望我的文字能为你带来更多的价值,也希望我们能在这个充满知识与灵感的旅程中,共同成长,一起进步。如果本篇文章有错误,还请大佬多多指正,再次感谢你的陪伴,期待与你在未来的文章中再次相遇!⛅️🌈 ☀️