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:

c 复制代码
process:process.c main.c
	gcc -o $@ $^
.PHONY:clean
clean:
	rm -f process

main.c

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

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

c 复制代码
#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);

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

相关推荐
所待.3834 分钟前
小小扑克牌算法
java·算法
大耳朵土土垚7 分钟前
【Linux 】开发利器:深度探索 Vim 编辑器的无限可能
linux·编辑器·vim
极客小张15 分钟前
基于STM32MP157与OpenCV的嵌入式Linux人脸识别系统开发设计流程
linux·stm32·单片机·opencv·物联网
x66ccff20 分钟前
【linux】4张卡,坏了1张,怎么办?
linux·运维·服务器
憧憬成为原神糕手23 分钟前
c++_list
开发语言·c++
idealzouhu26 分钟前
Java 并发编程 —— AQS 抽象队列同步器
java·开发语言
爱吃油淋鸡的莫何26 分钟前
Conda新建python虚拟环境问题
开发语言·python·conda
眰恦37433 分钟前
数据结构--第六章图
数据结构·算法
闲人编程34 分钟前
Python实现日志采集功能
开发语言·python·fluentd·filebeat·日志采集