Linux小程序 —— 进度条

打印 上一主题 下一主题

主题 528|帖子 528|积分 1584

前言:经过这么多天的学习,想必大家学到了许多Linux知识,本日我们来用Linux来实现我们的第一个小程序 — — 进度条



   本篇告急内容将会实现三个版本的进度条:
  

  • 简单原理版本
  • 实际工程实践版本
  • 拓展版本
  

   在实现进度条之前,我们先了解一些之前没提到过的知识,以便我们明白
  

  

1. 缓冲区的概念

我们先来分析下面几段代码感受一下行缓冲区的存在:
在Linux当中以下代码的运行效果是什么样的?
  1. #include <stdio.h>
  2. #include <unistd.h>                                                                                                                                                                    
  3.   
  4. int main()
  5. {
  6.     printf("你能看见我嘛\n");
  7.     sleep(2);
  8.     return 0;
  9. }
复制代码
  这段代码运行效果显而易见:printf函数直接打印内容,然后休眠2秒。
  对于大家大概没有什么难度。那如果我们修改一下代码。
  1. #include <stdio.h>
  2. #include <unistd.h>                                                                                                                                                                    
  3.   
  4. int main()
  5. {
  6.     printf("你能看见我嘛");
  7.     sleep(2);
  8.     return 0;
  9. }
复制代码

     缓冲区的概念
  
通过视频我们发现,我仅仅是将\n删除了,但是却带来了完全不一样的运行效果:先休眠2秒,然后才是printf函数打印内容
   那么为什么会出现这种情况呢? C语言实行代码的逻辑不应该是从上至下实行吗?
  

  • 按照 C语言实行代码的逻辑printf确实已经运行了,只不过内容没有被表现出来!
  • 内容地点的地区则是在输出缓冲区中!
  C/C++语言,会针对尺度输出,给我们提供默认的缓冲区
   fflush函数可以刷新缓冲区,如果我们想立马显现可以用函数刷新fflush(),而\n是一种刷新的计谋——行刷新,所以\n也能立马显现!
  
2. \r&&\n

   概念:
  

  • \r: 回车,使光标回到本行首格
  • \n: 换行,使光标移到下一行
  光说大概大家不太明白,我们来实操看看:
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. int main()
  4. {
  5.         int cnt = 10;
  6.         while(cnt)
  7.         {
  8.                 printf("%d\r", cnt--);
  9.                 fflush(stdout);
  10.                 sleep(1);
  11.         }
  12.         return 0;
  13. }
复制代码

     回车 \r
  
我们可以看到在输出下一个数之前都让光标先回到本行首格。
但是为什么输出效果和我预想的完全不一样?


printf("%-2d\r", cnt--);
我们以两位字符进行输出,-则是表示靠左对齐,就可以正常输出了!

3. 进度条

在进行上面的铺垫之后,我们开始编写我们的第一个小程序。我们将用两个源文件和一个头文件,一个说明,一个调用,一个实现
   test.c:实现
test.h:说明
main.c:调用
  1. // Makefile:
  2. mytest:test.c main.c
  3.      gcc -o $@ $^
  4. .PHONY:clean
  5. clean:
  6.      rm -rf mytest
复制代码

3.1 版本一

在版本一中,我们只要简单实现一下基本的功能,得到一个基本框架就足够了。
  1. // process_v1
  2. //test.h:申明
  3. pragma once
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <unistd.h>
  7.   
  8. // 定义进度条的总长度,因为有'\0'的存在所以设为101
  9. #define SIZE 101
  10. // 定义进度条的当前进度
  11. #define MAX_RATE 100
  12. // 进度条的符号
  13. #define STYLE '#'
  14. // 进度条的休眠时间
  15. #define STIME 1000*15
  16. void process_v1();
  17. .............
  18. //test.c:实现
  19. #include "test.h"
  20. // 旋转光标
  21. const char *str = "|/-\";
  22. // \\:才能表示一个'\'
  23. void process_v1()
  24. {
  25.      int rate = 0;
  26.      //初始化进度条全为'\0'
  27.      char bar[SIZE] = {0};
  28.          //循环打印
  29.          int num = strlen(str);
  30.      while(rate <= MAX_RATE)
  31.      {
  32.      // 进度条的打印格式
  33.      // -100:先取好[]的范围,然后靠左打印。
  34.          printf("[%-100s][%d%%][%c]\r", bar, rate, str[rate%num]);      
  35.      // 刷新缓冲区                                                                                                                                   
  36.          fflush(stdout);
  37.      // 休眠时长
  38.          usleep(STIME);
  39.      // 填充符号
  40.          bar[rate++] = STYLE;
  41.      }
  42.      // 刷新
  43.      printf("\n");
  44. }
  45. .............
  46. //main.c:调用
  47. #include "test.h>
  48. int main()
  49. {
  50.         process();
  51.         return 0;
  52. }
复制代码

     进度条:版本一
  
我们的第一代进度条也就完成了,实现了基本的结构框架!而我们的进度条,肯定不能干自己的,一定是和某种使命关联起来的!

3.2 版本二

我们将循环改成内部维护一个简单的静态缓冲区,每次往缓冲区里面增加内容然后刷新缓冲区内容就可以
   不能一次将进度条打印完毕,否则不能与场景更好的联合
  1. // process_v2
  2. //test.h:申明
  3. #pragma once
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <unistd.h>
  7.   
  8. #define SIZE 101
  9. #define MAX_RATE 100
  10. #define STYLE '#'
  11. #define STIME 1000*15
  12. typedef void(*callback_t)(int); // 回调函数        
  13. // 这里我们也可以使用函数指针                                                                                                                                                                                    
  14. void process_v2(int);                                 
  15. ~                           
  16. .............
  17. //main.c:调用
  18. #include "test.h"
  19.   
  20. #define TARGET_SIZE 1024*1024 // 模拟下载软件的大小
  21. #define DSIZE 1024*10 // 模拟下载的速度
  22.   
  23. //void download()
  24. //{
  25. //    int target = TARGET_SIZE; // 软件总体积
  26. //    int total = 0; // 当前下载的大小
  27. //
  28. //    while(total < target)
  29. //    {
  30. //        usleep(STIME); // 用休眠时间,模拟下载时间
  31. //        total += DSIZE;
  32. //       process_v2(total*100/target);                                                                                                                                                  
  33. //    }
  34. //    printf("\n");
  35. //}
  36. // 回调函数
  37. void download(callback_t cb)
  38. {
  39.     int target = TARGET_SIZE; // 软件总体积
  40.     int total = 0; // 当前下载的大小
  41.     while(total < target)
  42.     {
  43.         usleep(STIME); // 用休眠时间,模拟下载时间
  44.         total += DSIZE;
  45.         int rate = total*100/target;   
  46.         cb(rate);                                                                                                                                               
  47.     }
  48.     printf("\n");
  49. }
  50.   
  51. int main()
  52. {
  53.     download(process_v2);
  54.     return 0;
  55. }
  56. .............
  57. //test.c:实现
  58. #include "test.h"
  59.   
  60. const char *str = "|/-\";
  61. void process_v2(int rate)
  62. {
  63.     static char bar[SIZE] = {0};
  64.     int num = strlen(str);
  65.    
  66.     if(rate <= MAX_RATE && rate >= 0)                                                                                                                                                  
  67.     {
  68.         printf("[%-100s][%d%%][%c]\r", bar, rate, str[rate%num]);
  69.         fflush(stdout);
  70.         bar[rate] = STYLE;
  71.     }
  72.     if(rate == MAX_RATE)
  73.     {
  74.         // 重新刷新为0
  75.         memset(bar, '\0', sizeof(bar));
  76.     }
  77. }
复制代码

     进度条:版本二
  
我们也能完成进度条的实现,最后我们在优化一下,变成我们的版本三!。

3.3 版本三

因为版本二已经能将进度条完美的出现了,我们版本三,只是在二的底子上,美化一下,所以只是简单修改一点代码!

  1. // test.h
  2. #define STYLE_DEADER '>'
  3. #define STYLE_BODY '='
  4. typedef void (*callback_t)(double);
  5. .............
  6. // main.c
  7. // 我们在下载时,模拟下载中断的状态
  8. void download(callback_t cb)
  9. {
  10.     int target = TARGET_SIZE; // 软件总体积
  11.     int total = 0; // 当前下载的大小
  12.     while(total <= target)
  13.     {
  14.         usleep(STIME); // 用休眠时间,模拟下载时间
  15.         total += DSIZE;
  16.         double rate = total*100/target;
  17.         // 我们让下载进度永远维持在50%左右
  18.         if(rate > 50.0)
  19.         {
  20.                 total = target/2;
  21.         }  
  22.         cb(rate);                                                                                                                                               
  23.     }
  24.     printf("\n");
  25. }
  26. .............
  27. // test.c
  28. if(rate <= MAX_RATE && rate >= 0)
  29. {
  30.     // 设置cnt是为了在下载终止时,光标依然能变化
  31.     cnt++;
  32.     cnt = cnt > num ? 0 : cnt;
  33.     // \033[1;47;30m ... \033[0m 则是更改输出时字体和背景颜色
  34.     printf("加载中...\033[1;47;30m%-100s\033[0m][%.1lf%%][%c]\r", bar, rate, str[cnt]);                                                      
  35.     fflush(stdout);
  36.     if(rate < MAX_RATE)
  37.     {
  38.         bar[(int)rate] = STYLE_BODY;
  39.         bar[(int)rate+1] = STYLE_HEADER;
  40.     }
  41.     else{
  42.            bar[(int)rate] = STYLE_BODY;
  43.     }
  44. }
复制代码

     进度条:版本三
  
我们可以发现,我们修改了字体颜色和配景,设置测试了大概碰到的中断情况,光标依旧会变革。当然了进度条另有许多情景,等候着各位开发!

4. 总结拓展

拓展:
关于print带颜格式化输出,我在这里推荐一篇博客,有兴趣的可以去了解一下
print带颜格式化输出

总结:
本篇我们简单了解了一下缓冲区,以及换行'\n'与回车'\r'的基本概念,然后由浅入深的先容了三个版本的进度条,当然了美化方式各位都不一样,都是可以的,我们的Linux第一个小程序就讲到这里

谢谢大家支持本篇到这里就竣事了


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

钜形不锈钢水箱

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表