当我们在使用电脑或者手机下载东西的时候我们经常会看到类似于下面的东西:

这个正在往前走的蓝色横线就是一个进度条,相信大家都不会很陌生,那么我们在Linux下进度条虽然没有这么好看,但是效果都一样哈。

那么问题来了我们自己要怎么设计一个进度条呢?

在写之前咱们先普及一点知识,我们都知道,Linux下有三种缓冲方式:

  1. 无缓冲:顾名思义,就是没有缓冲,只要你输入随即就会给你输出出来,典型代表就是stderr。
  2. 行缓冲:就是把一行数据写满,遇到换行才执行I/O操作,一般是1024个字节,典型代表就是键盘操作。
  3. 全缓冲:只有把缓冲区写满才会执行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 }                                                                                                                                                                                                                

看看效果:


好了到此我们模拟的进度条就大功告成了。