Linux下diy程序:进度条

我们在Linux终端下载的进度条一般是这样的,我们来实现一个

1.背景知识

  1. 回车换行

    默认C语言下'\n'是回车加换行,但回车和换行是两个概念,回车是让光标回到当前行最开始处,换行是从当前位置换到下一行的相对位置;

    回车是\r

  2. 缓冲区

    下面这段代码逻辑上说,是先打印hello再休眠2s,但实际上是先休眠再打印,为什么呢?因为缓冲区没有被刷新,如果是printf("hello\n"); 由于\n的存在,会刷新缓冲区,直接打印在显示器上,系统会默认给我们打开三个流,标准输入,标准输出(stdout),标准错误,如下所示,因为printf之后,缓冲区没刷新,内容还在缓冲区,没有打印在显示器上,执行完休眠后程序即将结束,强制刷新

cpp 复制代码
    1 #include "ProcessBar.h"
    2 
    3 int main()
    4 {
    5     printf("hello");                                                                                                                                                                                                           
    6     sleep(2);
    7     return 0;
    8 }

sleep头文件是unistd.h

有没有什么办法强制刷新呢?fflush

cpp 复制代码
    1 #include "ProcessBar.h"
    2 
    3 int main()
    4 {
    5     printf("hello");    
    6	  fflush(stdout);                                                                                                                                                                                                       
    7     sleep(2);
    8     return 0;
    9 }

写一个倒计时

思想是打印完一个数字,接着回车,光标回到该行开头处,打印下一个数字覆盖当前数字

cpp 复制代码
    1 #include "ProcessBar.h"
    2 
    3 int main()
    4 {
    5     int cnt=9;                                                                                                                                                                                                                
    6     while(cnt>0)
    7     {
    8         printf("%d\r",cnt);//回车\r,每次打印完,回到行最左侧
    9         fflush(stdout);//强制刷新缓冲区,让缓冲区的内存打印到显示器上
   10         sleep(1);//休眠1s,不然打印太快,根本看不到
   11         cnt--;
   12     }
   13     printf("\n");
   14     return 0;
   15 }

运行结果,先输出hello再休眠2s

如果cnt是10的话,倒计时过程中会出现下面这种现象,因为显示器是字符设备,我们平时看到打印123,不是数值,而是打印123三个字符;刚开始打印10,是2个字符,之后只是1个字符,9覆盖了1,但是0还在;printf("%2d\r",cnt);就可以了,每次打印两个字符,没有两个就打印1个,默认右对齐,也可以加-进行左对齐printf("%-2d\r",cnt);

2.代码实现

2.1 版本一

main.c

cpp 复制代码
  1 #include "ProcessBar.h"                                                                                                                     
  2                                                                                                                                                                               
  3 int main()                                                                                                                                                                   
  4 {                                                                                                                                                                            
  5     processBar();                                                                                                                                                                                                                
  6     return 0;                                                                                                                                                            
  7 } 

Progress.h

cpp 复制代码
  1 #pragma once                                                                                                                                                                                                                     
  2 #include <stdio.h>
  3 #include <unistd.h>
  4 #include <string.h>
  5 extern void processBar();
  6 #define NUM 102//101个'=',只打印100个,因为最后一次循环的结果没有打印,加上\0共102
  7 #define BODY '='
  8 #define RIGHT '>'

Progress.c

cpp 复制代码
    1 #include "ProcessBar.h"
    2 char* loading="|/-\\";//用于实现加载动画
    3 void processBar()
    4 {
    5     int cnt=0;
    6     char c[NUM]={0};
    7     int len = strlen(loading);
    8     while(cnt<=100)
    9     {
   10         printf("[%-100s][%d%%][%c]\r",c,cnt,loading[cnt%len]);//显式进度条,完成比率,加载动画
   11 
   12         fflush(stdout);
   13         usleep(100000);//usleep的单位是微妙,1s=10^6us
   14         c[cnt]=BODY;//宏定义,方便后续更改
   15         cnt++;
   16         if(cnt<=99)
   17             c[cnt]=RIGHT;//因为cnt为100是最后一次打印,最后一次就不要>了                                                                                                                                                                                                      
   18 
   19     }
   20     printf("\n");
   21 }

命令模式下注释多行的指令起始行号,结束行号s/^/\/\//g

vim下多行减少一级缩进 :起始行号,结束行号>

2.2 版本2_结合调用场景

main.c

cpp 复制代码
  1 #include "ProcessBar.h"                                                                                       
  2 //模拟下载过程                                                                                                                                                                            
  3 void loading(callback_t cb)                                                                                                                                                  
  4 {                                                                                                                                                                            
  5     int total=1000,curr=0;                                                                                                                                
  6     while(curr<=total)                                                                                                                                                                                                           
  7     {                                                                                                                                                                                 
  8         int rate=curr*100/total;                                                                                                                                                                                         
  9         cb(rate);//调用进度条                                                                                                                                                                                                        
 10         curr+=10;                                                                                                                                                                                                        
 11         usleep(100000);                                                                                                                                                                                                  
 12     }                                                                                                         
 13     printf("\n");                                                                                             
 14 }                                                                                                             
 15                                                                                                               
 16 int main()                                                                                                    
 17 {                                                                                                             
 18     loading(processBar);                                                                                      
 19     return 0;                                                                                                 
 20 } 

ProcessBar.h

cpp 复制代码
  1 #pragma once                                                                                                                                                                                                                     
  2 #include <stdio.h>
  3 #include <unistd.h>
  4 #include <string.h>
  5 
  6 typedef void (*callback_t)(int);
  7 void loading(callback_t cb);
  8 extern void processBar(int rate);
  9 #define NUM 102
 10 #define BODY '='
 11 #define RIGHT '>'

ProcessBar.c

cpp 复制代码
    1 #include "ProcessBar.h"
    2 
    3 char* load="|/-\\";
    4 char c[NUM]={0};
    5 void processBar(int rate)
    6 {
    7     if(rate<0||rate>100) return;//临界条件控制                                                                                                                                                                                               
    8     int len = strlen(load);
    9 
   10     printf("[%-100s][%d%%][%c]\r",c,rate,load[rate%len]);
   11     fflush(stdout);
   12     c[rate++]=BODY;
   13     if(rate<=99)
   14         c[rate]=RIGHT;
   15 }

也可以进行带颜色的输出

cpp 复制代码
    1 #define NONE "\033[m"
    2 #define CYAN "\033[0;36m" //青色
    3 printf(CYAN"[%-100s][%d%%][%c]\r"NONE,c,rate,load[rate%len]);       

颜色配置参考文章如下
C语言输出颜色

相关推荐
70asunflower2 小时前
Python with 语句与上下文管理完全教程
linux·服务器·python
tritone2 小时前
学习Chef自动化配置管理工具,为了实践环境部署,我选择了**阿贝云**的**免费虚拟主机**和**免费云服务器**来搭建测试平台。
服务器·学习·自动化
j_xxx404_2 小时前
Linux:调试器-gdb/cgdb使用
linux·运维·服务器
艳阳天_.2 小时前
华为云欧拉服务器问题记录
运维·服务器·华为云
驱动探索者2 小时前
AMD EPYC 服务器 CPU 学习
运维·服务器·学习·cpu
市安2 小时前
docker命令知识点1
运维·docker·云原生·容器·eureka
鸣弦artha2 小时前
TabBar标签页组件详解
linux·git·ubuntu
向上的车轮3 小时前
openEuler 内核解读(五):Linux 内核模块 “Hello World” 示例
linux·openeuler
SmartRadio3 小时前
ESP32-S3实现KVM远控+云玩功能 完整方案
运维·python·计算机外设·esp32·kvm·云玩