进度条我将实现三个版本:
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 }