当前位置:   article > 正文

【Linux系统编程六】:Linux小程序:进度条实现(make/makefile自动构建)_makefile输出编译进度

makefile输出编译进度

【Linux系统编程六】:Linux小程序:进度条实现(make/makefile自动构建)

Ⅰ.倒计时实现

①.回车换行概念

要想实现进度条,我们需要理解两个概念,回车换行与缓冲区。
在C语言中回车换行就是'\n'
但在现实中回车和换行是两码事。
回车:回到最开始的位置。
回车在C语言中是'\r'
换行:从当前位置垂直换到下一行,位置不变。

我们接下来要实现这样的功能:

我们知道每打印一个字符,光标就会往后挪动。我们想每次打印完字符都要回到一开始的位置。这样原来的数据就会被覆盖。新数据就会显示出来。这就是倒计时实现的原理。

②.缓冲区概念

缓冲区:C中的缓冲区是行缓冲区,为什么交行缓冲区呢?因为只有当遇到换行’
\n’时,缓冲区的内容才会出来,不然就要等到程序结束后,缓冲区的内容才能出来。
在这里插入图片描述
sleep是让程序等上1秒再将结束
在这里插入图片描述
结果也正是这样。先打印,然后延迟1秒结束。

那么接下来这样呢?
在这里插入图片描述
没有了换行’\n’结果会如何呢?
在这里插入图片描述

在这里插入图片描述
结果却是等待了约1秒后xiaotao才被打印出来,并且命令行直接在后面接着上去了。
命令行在后面我们是可以理解的,因为没有换行,所以就直接跟在后面了。
但为什么延迟了1秒才打印出来呢?明明C程序中的顺序是先打印后延迟呀。

这其实就是缓冲区的原因,没有换行,打印的内容被放在了缓冲区里出不来。然后又等了一秒钟,程序结束了,缓冲区的内容才被释放出来。
这就说明确实存在缓冲区的,并且满足只有当程序结束后才可以释放。
那我们如果想让缓冲区的内容立即释放该怎么办呢?
fflush(FILE*stream)
C语言会默认帮我们打开三个流:标准输入流,标准输出流,标准错误流。

在这里插入图片描述
所以我们只要使用fflush(stdout)就可以将缓冲区的内容释放出来。
不要慢慢悠悠的出来,我要立刻出来
消息是stdout打的,暂存在stdout中,现在要强制刷新

在这里插入图片描述
在这里插入图片描述

既然回车换行和缓冲区两个概念理解后,我们就可以写倒计时器了。

 59   int main()                              
   60 {                                                  
   66   int cnt =10;                          
   67   while(cnt>=0)                         
   68   {                                     
   69     printf("%-2d\r",cnt);   //左对齐,要求拥有两个位置            
   70    fflush(stdout);                      
   71     cnt--;                              
   72                                         
   73     sleep(1);                           
   74   }                                     
   75   printf("\n");                         
   76   return 0;       
   77 }                          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

Ⅱ.进度条实现version1

我们想要的进度条是这样的:

.jpg

在这里插入图片描述

进度条的两段有两个括号,进度条在里面挪动从0%–100%,进度条是一个箭头形状,后面还有着进度比显示,后面还有着进度运行的状态。并且这个进度条还有颜色。
该小程序是直接用make/makefile自动构建,将processbar.c文件和main.c文件直接编译。
在这里插入图片描述

1.首先我们需要定义一个char类型数组,这里就是存放着进度条,而这个进度条形状自己定义。实现进度条的原理其实跟倒计时类似,都是每次新的内容需要覆盖旧的内容,也就是每次输出都需要回车,不同的是,进度条需要每次输出比上次要多输出一个,这样每次覆盖就可以显示往后挪动了。
2.我们定义的数组大小应该为102,因为里面需要存放102个数据,一般我们数据加载是不是都显示从0%~100%,所以我们需要循环101次,然后最后还需要存放’\0’。
3.要注意数组一开始需要初始化。
4.需要预先在[]中间看出100个空间,这样左[就在左边,]右括号就在右边,进度条就往右括号去。
5.然后进度条后面还需要显示进度情况,进度情况其实就是循环的次数,在C语言中两个%%表示%。。
6.我们想要让数组每次都要多出一个数据,那么只要在循环时,先打印出数组内容,再往数组里插入数据。这样就可以实现下一次循环数组的内容覆盖上一次的内容,并且看上去往后挪动了。比如第一次数组里什么都没有,第一次打印空,然后往数据里插入进度符号,第二次循环,符号上次的内容打印出符号,然后又往数组里插入数据,第三次循环,覆盖上次内容再打印出符号,以此类推。
7.我们还需要一个箭头一直往后走,该怎么弄呢?每次先打印完数据后,再往数组里插入符号,每次插入完符号后都需要让插入的位置往后挪动也就是++,所以我们只需要在++后的位置上添加箭头符号即可。

在这里插入图片描述

void processbar()                                               
   26   int cnt=0;                                                                                
   27                                                                 
   28    char bar[NUM];                                                               
   29    //初始化                                                                                     
   30    memset(bar,'\0',sizeof(bar));                                                          
   31    while(cnt<=100)                                                      
   32    {                                                                                              
   33      printf("[%-100s][%d%%]\r",bar,cnt);
   //先将内容打印出来                                                                                                   
   34     fflush(stdout);//将缓冲区内容刷新释放                                                                        
   35      bar[cnt++]=STYLE;//再往该位置插入符号,该位置往后挪动,为了下次插入符号。                                                                     
   36      if(cnt<100)bar[cnt]='>';//可以让++后的位置上放入箭头符号,不过要注意的是cnt只能循坏到100,再++就变成101,那么\0的位置就被覆盖了,所以不能再插入。                
   37      usleep(50000);                                                                           
   38    }                                                                                        
   39    printf("\n");                                                             
   40 }                 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

最后我们还可以加上进度状态,就是进度条在挪动,它就会转动。
这该如何实现呢?
原理一样,只需要一个字符数组里存放着 - / | \ 几个符号,然后每次打印都覆盖上一次的内容,就可以出现一个旋转的东西了。

 const char* label="-/|\\";
//注意两个\\第一个是转义字符
void processbar()                                               
   26   int cnt=0;                                                                                
   27    int len=strlen(label);                                                            
   28    char bar[NUM];                                                               
   29    //初始化                                                                                     
   30    memset(bar,'\0',sizeof(bar));                                                          
   31    while(cnt<=100)                                                      
   32    {                                                                                              
   33       printf("[%-100s][%d%%][%c]\r",bar,cnt,label[cnt%len]);
   //先将内容打印出来                                                                                                   
   34     fflush(stdout);//将缓冲区内容刷新释放                                                                        
   35      bar[cnt++]=STYLE;//再往该位置插入符号,该位置往后挪动,为了下次插入符号。                                                                     
   36      if(cnt<100)bar[cnt]='>';//可以让++后的位置上放入箭头符号,不过要注意的是cnt只能循坏到100,再++就变成101,那么\0的位置就被覆盖了,所以不能再插入。                
   37      usleep(50000);                                                                           
   38    }                                                                                        
   39    printf("\n");                                                             
   40 }                 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

Ⅲ.进度条实现version2

进度条可以实现后,我们接下来是模拟使用进度条,进度条怎么使用呢,如何被调用呢?
在不同的场景是不同的,一般循环操作是放在进度条里的,正常的进度条只打印它一个状态时的进度,是由使用它的人来决定从什么地方开始加载进度条。所以循环部分是在进度条的外部被使用者操作的。而进度条程序只需要接收一个比率,然后只打印该比率下的进度条。

 //v2版本
    9 //是如何调用进度条的,一般不讲循环放在进度条里,进度条只是打印一个比率时的进度
     const char* label="-/|\\";
   10  char bar[NUM]={0};//直接可以变成全局
   11 void processbar(int rate)//只需要一个比率
   12 {
   13    int len=strlen(label);
   14 
   15      printf("[%-100s][%d%%][%c]\r",bar,rate,label[rate%len]);
   16      fflush(stdout);
   17      bar[rate++]=STYLE;
   18      if(rate<100)bar[rate]='>';
   19 }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
//v2版本
 65 int main()
 66 {
 67   int total=1000;//比如总容量为1000MB
 68   int cur=0;//从一开始下载
 69   while(cur<=total)
 70   {
 71     processbar(cur*100/total);//rate=cur*100/total,表示加载的进度
        //调用进度条程序
 72     cur+=10;//每次加载的进度,每次更新多少,,,
 73     usleep(50000);
 74   }
 75   printf("\n");
 76   return 0;
 77 }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

Ⅳ.进度条实现version3

利用函数回调的方法来调用进度条。

 void init()
   21 {
   22    memset(bar,'\0',sizeof(bar));
   23 }
//v3:模拟一个安装下载
  7 
  8 typedef void (*call_t)(int);//定义一个函数指针类型
  9  //返回值是void,函数参数是int
 10 void downloan(call_t cd)//定义一该该类型的变量
 11 {
 12   int total=1000;
 13   int cur=0;
 14  while(cur<=total)
 15  {
 16   int rate=cur*100/total;
 17   cd(rate);//将rate串给cd,而cd就是processbar进度条程序,函数回调,调用进度条
 18   cur+=10;
 19   usleep(50000);
 20  }
 21  printf("\n");
 22 }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
int main()
 24 {                                                                                                    
 25   printf("downloan1\n");
 26   downloan(processbar);//我们就将进度条程序传给cd。
 27   init();//当进度满了,那么下一次就无法正常打印出来了,所以当进度条打印完后需要清理一下,进度条,这样下次才可以打印出来。
 28  
 29   printf("downloan2\n");
 30   downloan(processbar);
 31   init();
 32 
 33   printf("downloan3\n");  
 34   downloan(processbar);
 35   init();
 36   
 37   printf("downloan4\n");  
 38   downloan(processbar);
 }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

最后说一下如何让进度条变成有颜色的,C语言中是可以进行颜色输出的。

printf("以下是测试文字颜色:\n");
printf("\033[30m 黑色\033[m\n");//中间的空格可去
printf("\033[31m 红色\033[m\n");
printf("\033[32m 绿色\033[m\n");
printf("\033[33m 黄色\033[m\n");
printf("\033[34m 蓝色\033[m\n");
printf("\033[35m 紫色\033[m\n");
printf("\033[36m 浅蓝\033[m\n");
printf("\033[37m 白色\033[m\n");
————————————————
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在这里插入图片描述

 printf(LIGHT_BLUE"[%-100s]"NONE"[%d%%][%c]\r",bar,rate,label[rate%len]);
 只需将要上色的颜色放在上面两个位置即可。NONE是关闭,必须放在后面。
 前面选择自己喜欢的颜色即可。
  • 1
  • 2
  • 3
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/313014
推荐阅读
相关标签
  

闽ICP备14008679号