linux--进度条


本篇文章我们将来尝试写一个简单的小程序–进度条。

搭建环境

在这之前,我们要先搭建好一个框架,如下:

先依次创建好一个头文件(pb.h)用以声明和定义宏,一个源文件(pb.c)用于书写进度条源代码,一个源文件(main.c)用于测试以及后续搭建实际的场景,以及makefile。

makefile:

版本1

我们先从最简单的版本开始讲起,这个版本的进度条只是以单独的一个函数形式呈现出来,主要是为了先搞清楚程序的运行原理。

进度条一般是出现在下载任务,加载任务的某些场景中的,我们用rate来模拟当前下载的进度,MAX_RATE来模拟总进度,我们先创建一个字符数组用来存放我们要打印的进度条,再把该数组全部初始化为’\0’,然后循环打印,每次打印休眠一段时间,模拟下载所需的时间,最后初代形式就如下图所示:

我们发现打印的结果如下图所示:
在这里插入图片描述

这很明显不符合我们的预期,我们预期的是在同一行不断增加字符长度而不是往下每一行重新打印,所以我们要把\n换成\r,\r的作用是使光标回到当前行的开头。修改后的结果如下:

打印的结果如下:
在这里插入图片描述

我们发现,光标位置是不会往下走了,但是什么东西都没有打印出来,这是因为数据都被放在缓冲区了,我们需要用fflush(stdout)刷新一下输出流,把在缓冲区的东西在终端上打印出来
由于sleep时间过短,不好观察现象,我们就使用vim环境特有的库函数usleep,它的数字单位是微秒,需要引用的头文件是#include <unistd.h>,同时我们也可以用宏来定义这些变量以便于后续修改。为了美观和便于观察,我们还可以将当前下载进度百分比和旋转图标打印出来,图标我们用一个str数组保存下来,然后不断循环打印数组里的图标,所以第一个版本的完整代码如下:

版本2

接下来我们来讲版本2,我们通过版本2要将进度条与实际的情况联系起来,在版本1中,我们只能在函数体内运行我们的进度条,但真实情况是,我们每传递一次进度,这个进度条函数就在自己内部打印一次,然后再更新一次进度参数,进度条函数再自己打印一次,这样的话,我们就应该在外部进行循环打印,而进度条函数应该只是作为一个接口,所以我们首先就要将循环搬到函数外去,这样的话,我们就不能再像版本1一样初始化bar数组了,因为每次进入这个函数,都会重新初始化,不会保存上一次运行结束后的样子,所以我们用static修饰字符数组,使他出了自己的范围也不会被销毁。然后为了贴合实际工程,我们用一个头文件来存放头文件 宏 以及函数的声明,一个源文件来书写进度条函数,再用一个源问件来模拟实景场景进行测试。

process.h
在这里插入图片描述

main.c
在这里插入图片描述

process.c
在这里插入图片描述

这样写固然能实现功能,但我们实际情况是有一个总的资源大小,然后每过一段时间会下载一定的资源,我们把这两个数相除来表示当前进度作为参数传给process_v2函数,所以我们还可以优化成这样:

但这样还不是我们版本2的最终形态,因为在实际场景中,我们是会进行某种任务的通知,动态更新进度条,这里就要使用到回调函数,回调函数的使用和声明如下:

再结合process_v2,这就是版本2的完整代码。

版本3

版本3就是在版本2的基础上再做一些美化,真实情况下,进度条一般不会是#而是类似于箭头的样子,我们还可以为进度条添加颜色,C语言是支持此类语法的,感兴趣的小伙伴可以去搜一下,这里就不再过多赘述了。

功能上也有一些优化,我们一般在下载卡住的时候,进度没有动而图标应该是一直在旋转的,意思是当前进度虽然卡住了但实际上还在继续下载,版本2和版本1都没法实现这样的功能,所以我们要切断str数组打印与否和rate的联系,单独拿出来循环打印,具体实现如下:
在这里插入图片描述

所以最终完整代码如下:
makefile:

process:process.c main.c
	gcc -o $@ $^
.PHONY:clean
clean:
	rm -f process

main.c

void download(callback_t cb)
{
    int testcnt = 100;
    int target = TARGET_SIZE;
    int total = 0;

    while(total <= target)
    {
        usleep(STIME); // 用简单的休眠时间,模拟本轮下载花费的时间
        total += DSIZE;
        double rate = total*100.0/target;
        if(rate > 50.0 && testcnt) {
            total = target/2;
            testcnt--;
        }
        cb(rate); // 回调函数
    }
    cb(MAX_RATE); // 回调函数
    printf("\n");
}


// 下载的软件
int main()
{
    download(process_v3);
    return 0;
}

process.c

void process_v3(double rate)
{
    // version 2
    // TODO
    static char bar[SIZE]= {0};
    static int cnt = 0;
    int num = strlen(str);
    if(rate <= MAX_RATE && rate >=0)
    {
        cnt++;
        cnt = (cnt >= num ? 0 : cnt); //cnt %= num;
        printf("加载中... [\033[31;44m%-100s\033[0m][%.1f%%][%c]\r", bar, rate, str[cnt]);
        fflush(stdout);
        if(rate < MAX_RATE)
        {
            bar[(int)rate] = STYLE_BODY; //'='
            bar[(int)rate+1] = STYLE_HEADER; //'>'
        }
        else
        {
            bar[(int)rate] = STYLE_BODY;
        }
    }
    //if(rate == MAX_RATE) memset(bar, '\0', sizeof(bar));
}

process.h

#pragma once

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

#define SIZE 101
#define MAX_RATE 100
#define STYLE '#'
#define STIME 1000*40

#define STYLE_BODY '='
#define STYLE_HEADER '>'

typedef void (*callback_t)(double);

void process_v3(double);

以上就是关于进度条三个版本的全部内容(*≧ω≦)

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

偷吃橙子的喵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值