当我们在使用电脑或者手机下载东西的时候我们经常会看到类似于下面的东西:
这个正在往前走的蓝色横线就是一个进度条,相信大家都不会很陌生,那么我们在Linux下进度条虽然没有这么好看,但是效果都一样哈。
那么问题来了我们自己要怎么设计一个进度条呢?
在写之前咱们先普及一点知识,我们都知道,Linux下有三种缓冲方式:
- 无缓冲:顾名思义,就是没有缓冲,只要你输入随即就会给你输出出来,典型代表就是stderr。
- 行缓冲:就是把一行数据写满,遇到换行才执行I/O操作,一般是1024个字节,典型代表就是键盘操作。
- 全缓冲:只有把缓冲区写满才会执行IO操作,典型代表就是磁盘读写。
而这次我们设计的进度条恰好使用的是printf函数,printf输出函数是一个行缓冲函数,先写到缓冲区,满足条件就将缓冲区刷到对应文件中。满足下列条件之一,缓冲区都会刷新:
(1)缓冲区填满
(2)写入的字符中有’\n’ ‘\r’
(3)调用fflush刷新缓冲区
(4)调用scanf从缓冲区获取数据时,也会刷新新缓冲区。
由于输出函数是行缓冲类型的。所以我们需要使用缓冲区刷新函数fflush来输出。否则我们看到的进度条将是一段一段输出的。
fflush:
fflush + 函数名, 清除读写缓冲区,需要立即把输出缓冲区的数据进行物理写入时。
fflush(stdin) 刷新标准输入缓冲区,把输入缓冲区里的东西丢弃[非标准]
fflush(stdout) 刷新标准输出缓冲区,把输出缓冲区里的东西打印到标准输出设备上
这里不能用\n 而要用\r:‘\n’表示的是换行,将光标指向下一行的开头位置。\r则是每次回到行首。
下面我们看看普通进度条的代码:
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <string.h>
4 int main()
5 {
6 int i=0;
7 char bar[100];
8 memset(bar,0,sizeof(bar));
9 const char* lable="/-|\\";
10 while(i<=100)
11 {
12 printf("[%-100s][%d%%][%c]\r",bar,i,lable[i%4]);
13 bar[i]='#';
14 usleep(10000);
15 i++;
16 fflush(stdout);
17 }
18 printf("\n");
19 return 0;
20 }
升级版进度条
下面我们说说彩色进度条:
printf函数可以通过输出特定的转义序列来实现输出字符的颜色和状态。
转义序列以控制字符’ESC’开头。该字符的ASCII码十进制表示为27,十六进制表示为0x1B,八进制表示为033。多数转义序列超过两个字符,故通常以’ESC’和左括号’[‘开头。该起始序列称为控制序列引导符(CSI,Control Sequence Intro),通常由 ’\033[‘ 或 ’\e[‘ 代替。
一般格式如下:(显示方式指的是样式,前景色是30+颜色值,背景色是40+颜色值,字符m表示结束)
\033[显示方式;前景色;背景色m + 输出字符串
或者
\e[显示方式;前景色;背景色m + 输出字符串
常见参数如下:
显示方式:0(默认)、1(粗体/高亮)、22(非粗体)、4(单条下划线)、24(无下划线)、5(闪烁)、25(无闪烁)、7(反显、翻转前景色和背景色)、27(无反显)
颜色:0(黑)、1(红)、2(绿)、 3(黄)、4(蓝)、5(洋红)、6(青)、7(白)
// 字体颜范围(前景颜色):30~39
30:黑 31:红 32:绿 33:黄 34:蓝色 35:紫色 36:深绿 37:白色
// 字背景颜色范围(背景颜色):40~49
40:黑 41:深红 42:绿 43:黄色 44:蓝色 45:紫色 46:深绿 47:白色
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <string.h>
4 int main()
5 {
6 int i=0;
7 int j=0;
8 int color[]={1,2,3,4,5,6,7};
9 char bar[100];
10 memset(bar,0,sizeof(bar));
11 const char* lable="/-|\\";
12 while(i<=100)
13 {
14 printf("\033[3%dm[%-100s][%d%%][%c]\r",color[j],bar,i,lable[i%4]);
15 bar[i++]='#';
16 fflush(stdout);
17 if(i%15==0) //每隔15%换种颜色
18 {
19 ++j;
20 }
21 usleep(10000);
22 }
23 printf("\n");
24 return 0;
25 }
看看效果:
好了到此我们模拟的进度条就大功告成了。