进度条我将实现三个版本:
1 简单原理版本
2 实际工程实践版本
3 c语言扩展-设计颜色
首先我们需要有一些前置知识:关于行缓冲区和回车换行
行缓冲区:c/c++语言会针对标准输出给我们提供默认的缓冲区,这次的角色是输出缓冲区
输出的内容不会立马显示,而是放置在输出缓冲区内,只有当缓冲区刷新时我们才会看到输出的内容,而我们平时打印内容喜欢在其后加上\n ,其实\n就是一种刷新的策略(行刷新)
关于回车换行:
\n :回车+换行
\r :回车
编写进度条我们可以这样做:
每次多打印一个字符,且从头开始打印,形成覆盖效果
这里就需要用\r了,每打印完字符串后又重新回到开头,覆盖式地打印比前字符串多一个字符的字符串,因为每次打印都在同一行,视觉效果上就是进度条加载的模样了
进度条蓝图:
- 1 #pragma once
- 2
- 3 #include
- 4 #include
- 5 #include
- 6
- 7 #define SIZE 101
- 8 #define MAX_RATE 100
- 9 #define STIME 1000*40//休眠时间 ,1秒=1000000微秒,usleep以微妙为计时单位,但是1秒可能太慢了,我们将速度稍微调快一点
- 10 #define STYLE '#'
- 11
- 12 void process_v1();
- 1 #include"process.h"
- 2
- 3 const char *str = "|/-\\";
- 4
- 5 void process_v1()
- 6 {
- 7 int num = strlen(str);
- 8 char bar[SIZE];
- 9 memset(bar,'\0',sizeof(bar));
- 10 int rate = 0;
- 11 while(rate<=MAX_RATE)
- 12 {
- 13 printf("[%-100s][%d%%][%c]\r",bar,rate,str[rate%num]);//左对齐
- 14 fflush(stdout);//刷新输出缓冲区
- 15 usleep(STIME);//休眠(停顿一下)
- 16 bar[rate++] = STYLE;
- 17 }
- 18 printf("\n");
- 19 }
-
- 1 process:process.c main.c
- 2 gcc $^ -o $@
- 3
- 4 .PHONY:clean
- 5 clean:
- 6 rm -f process
- 1 #include"process.h"
- 2
- 3 int main()
- 4 {
- 5 process_v1();
- 6 return 0;
- 7 }
版本1的进度条是一次就打印完毕,不能平滑的与实际场景相结合,版本2就与实际场景相结合了,
做到:每下载一点就根据rate打印一次
- 1 #pragma once
- 2
- 3 #include
- 4 #include
- 5 #include
- 6
- 7 #define SIZE 101
- 8 #define MAX_RATE 100
- 9 #define STIME 1000*40
- 10 #define STYLE '#'
- 11 #define TARGET_SIZE 1024*1024//下载文件的总大小为1MB
- 12 #define DSIZE 1024*10//每次下载的大小
- 13 void process_v1();
- 14 void process_v2(int);
- 24 void process_v2(int rate)
- 25 {
- 26 int num = strlen(str);
- 27 static char bar[SIZE] = {0}; //设置成静态的数组,使之能保持上次的结果
- 28 if(rate>=0 && rate<=MAX_RATE)
- 29 {
- 30 printf("[%-100s][%d%%][%c]\r",bar,rate,str[rate%num]);
- 31 fflush(stdout);
- 32 bar[rate] = STYLE;
- 33 }
- 34 if(rate==MAX_RATE)
- 35 {
- 36 memset(bar,'\0',sizeof(bar));
- 37 }
- 38 }
- 1 #include"process.h"
- 2
- 3 void download()//下载函数
- 4 {
- 5 int total = 0;
- 6 int target = TARGET_SIZE;//下载文件的总大小
- 7 while(total<=target)
- 8 {
- 9 usleep(STIME);//休眠时间来模拟本轮下载花费的时间
- 10 total+=DSIZE;
- 11 process_v2(total*100/target);//显示下载进度
- 12 }
- 13 printf("\n");
- 14
- 15 }
- 16
- 17 int main()
- 18 {
- 19 download();
- 20 return 0;
- 21 }
- ~
- 1 #pragma once
- 2
- 3 #include
- 4 #include
- 5 #include
- 6
- 7 #define SIZE 101
- 8 #define MAX_RATE 100
- 9 #define STIME 1000*40
- 10 #define STYLE '#'
- 11 #define TARGET_SIZE 1024*1024
- 12 #define DSIZE 1024*10
- 13 #define STYLE_BODY '='
- 14 #define STYLE_HEADER '>'
- 15 typedef void (*callback_t)(double);//函数指针类型callback_t
- 16 void process_v1();
- 17 void process_v2(int);
- 18 void process_v3(double);
- 43 void process_v3(double rate)
- 44 {
- 45 int num = strlen(str);
- 46 static char bar[SIZE] = {0};
- 47 static int cnt = 0;
- 48 if(rate>=0 && rate<=MAX_RATE)
- 49 {
- 50 cnt++;
- 51 cnt = cnt>=num? 0:cnt;
- 52 printf("加载中……[%-100s][%.1f%%][%c]\r",bar,rate,str[cnt]);//未加上颜色
- 53 fflush(stdout);
- 54 if(rate<=MAX_RATE)
- 55 {
- 56 bar[(int)rate] = STYLE_BODY;
- 57 bar[(int)rate+1] = STYLE_HEADER;
- 58 }
- 59
- 60 }
- 61 }
若要加上颜色可以自己去搜索c语言颜色的代码,根据喜好自行变换即可
这里使用:
printf("加载中...[\033[33;44m%-100s\033[0m]][%.1f%%][%c]\r",bar,rate,str[cnt]);
- 19 void download2(callback_t cb)
- 20 {
- 21 int total = 0;
- 22 int target = TARGET_SIZE;
- 23 int cnt = 100;
- 24 while(total<=target)
- 25 {
- 26 usleep(STIME);//模拟下载花费的时间
- 27 total+=DSIZE;
- 28 double rate = total*100.0/target;
- 29 if(rate>50.0 && cnt)//模拟下载中进度条的停顿,但仍在下载
- 30 {
- 31 total = target/2;
- 32 cnt--;
- 33 }
- 34 cb(rate);//回调函数
- 35 }
- 36 cb(MAX_RATE);
- 37 printf("\n");
- 38
- 39 }
- 40
- 41
- 42 int main()
- 43 {
- 44 download2(process_v3);
- 45 return 0;
- 46 }