【Linux】编写第一个小步伐:进度条

打印 上一主题 下一主题

主题 529|帖子 529|积分 1587


1. 准备知识

1.1 简单认识几个函数

1.1.1 sleep()

  1. unsigned int sleep(unsigned seconds);
复制代码
  

  • 作用:让步伐休眠指定秒数,如:sleep(3); //让步伐休眠3秒
  • 与 Windows 上的 Sleep() 函数差异
  • 必要包含头文件<unistd.h>
  1.1.2 fflush()

  1. int fflush(FILE* stream);
复制代码
  

  • 作用:刷新缓冲区
  • 必要传入一个流
  • 必要包含头文件<stdio.h>
  1.1.3 usleep()

  1. int usleep(useconds_t usec);
复制代码
  

  • 作用:让步伐休眠指定微秒,如:usleep(100000); //让步伐休眠100000微秒(0.1秒)
  • 1秒 = 1000000微秒
  • 必要包含头文件<unistd.h>
  1.1.4 memset()

  1. void* memset(void* ptr, int value, size_t num);
复制代码
  

  • 作用:将 ptr 指向的内存块的前 num 个字节设置为指定的 value 值
  • 返回设置后的 ptr
  • 必要包含头文件<string.h>
  1.2 缓冲区

直接上代码观察现象
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. int main()
  4. {
  5.     printf("you can see me       ");
  6.     sleep(3);
  7.     return 0;
  8. }
复制代码
执行结果图

   

  • 首先要否定上面不切现实的想法,C语言是顺序执行的,以是 printf 函数一定先于 sleep 函数执行。
  • 那为什么 3 秒后才打印到屏幕上呢?当然是因为缓冲区!
  • printf 函数跑完后,输出的字符串是被保存到 C 对 IO 函数提供的一个缓冲区里了,在步伐退出的时候,缓冲区中的内容才被刷新到屏幕上
  • 我们必要使用上面讲的 fflush 函数把缓冲区中的内容提前强制刷新到屏幕上,使用方法:fflush(stdout);
  1.3 回车与换行

首先我要抛出一个概念:回车和换行是不一样的!
   

  • 回车( \r ):把光标放到当前行的开始。
  

   

  • 换行( \n ):把光标放到当前位置的下一行。
  

   

  • 以是理论上来讲,‘\n’ 和 ‘\r’ 一起用才是我们明确中的”回车“,即:把光标放到下一行最开始的位置。
  2. 编写入门版的进度条

2.1 根本逻辑

   

  • 进度 1% 打印 1 个字符,回车到开始的位置,刷新缓冲区;
  • 进度 2% 打印 2 个字符,回车到开始的位置,刷新缓冲区;

  • 进度 100% 打印 100 个字符,回车到开始的位置,刷新缓冲区,步伐停止。
  

2.2 美化结果

   

  • 进度条主体增长箭头显示
  • 显示进度百分比
  • 添加一个动态的旋转光标
  

2.3 代码实现

  1. // porcessbar.h
  2. #pragma once
  3. #include <stdio.h>
  4. #define NUM 103
  5. #define Body '='
  6. #define Head '>'
  7. // version 1
  8. void process();
复制代码
  1. // processbar.c
  2. #include "processbar.h"
  3. #include <string.h>
  4. #include <unistd.h>
  5. const char* lable = "|/-\";
  6. // version 1
  7. void process()
  8. {
  9.     char buffer[NUM];
  10.     memset(buffer, '\0', sizeof(buffer));
  11.     int cnt = 0;
  12.     int n = strlen(lable);
  13.     buffer[0] = Head;
  14.     while (cnt <= 100)
  15.     {
  16.         printf("[%-100s][%3d%%][%c]\r", buffer, cnt, lable[cnt % n]);
  17.         fflush(stdout);
  18.         buffer[cnt++] = Body;
  19.         if (cnt < 100)
  20.         {
  21.             buffer[cnt] = Head;
  22.         }
  23.         usleep(50000);
  24.     }
  25.     printf("\n");
  26. }
复制代码
2.4 执行结果




3. 编写升级版的进度条

   

  • 上面的进度条算是一个进度条吗?我们的进度条似乎在一个人玩单机呀,这样的进度条是没有意义的。
  • 进度条的进度应该是依靠于其他应用的,比如下载。
  • 下面我们模仿一个下载情况,并修改进度条,使进度条可以根据下载的进度,同步举行显示进度的工作。
  3.1 代码实现

  1. // processbar.h
  2. #pragma once
  3. #include <stdio.h>
  4. #define NUM 103
  5. #define Body '='
  6. #define Head '>'
  7. typedef void (*callback_t)(double);                // 函数指针类型
  8. // version 2
  9. void process_flush(double rate);
复制代码
  1. // processbar.c
  2. #include "processbar.h"
  3. #include <string.h>
  4. #include <unistd.h>
  5. const char* lable = "|/-\";
  6. // version 2: 进度是多少,你进度条能知道吗?另外,什么进度?依附于其他应用的,比如下载
  7. char buffer[NUM] = {0};
  8. void process_flush(double rate)
  9. {
  10.     static int cnt = 0;
  11.     int n = strlen(lable);
  12.     if (rate <= 1.0)
  13.     {
  14.         buffer[0] = Head;
  15.     }
  16.     printf("[%-100s][%.1f%%][%c]\r", buffer, rate, lable[cnt % n]);
  17.     fflush(stdout);
  18.     buffer[(int)rate] = Body;
  19.     if ((int)rate + 1 < 100)
  20.     {
  21.         buffer[(int)(rate + 1)] = Head;
  22.     }
  23.     if (rate >= 100.0)
  24.     {
  25.         printf("\n");
  26.     }
  27.     cnt++;
  28.     cnt %= n;
  29. }
复制代码
  1. // main.c
  2. #include "processbar.h"
  3. #include <time.h>
  4. #include <stdlib.h>
  5. #include <unistd.h>
  6. // 模拟文件大小
  7. #define FILESIZE (1024 * 1024 * 1024)
  8. // 模拟一种场景,表示一种下载任务
  9. void download(callback_t cb)    // 回调函数的形式
  10. {
  11.     srand(time(NULL) ^ 1023);   // 这样写只是为了让随机数更随机
  12.     int total = FILESIZE;
  13.     while (total)
  14.     {
  15.         usleep(10000);  // 下载动作
  16.         int one = rand() % (1024 * 1024);  // 一次下载的大小
  17.         total -= one;
  18.         if (total < 0)
  19.         {
  20.             total = 0;
  21.         }
  22.         // 当前的进度是多少?
  23.         int download = FILESIZE - total;
  24.         double rate = (download * 1.0 / FILESIZE) * 100.0;
  25.         cb(rate);
  26.     }
  27. }
  28. int main()
  29. {
  30.     download(process_flush);
  31.     return 0;
  32. }
复制代码
3.2 执行结果





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

本帖子中包含更多资源

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

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

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

本版积分规则

耶耶耶耶耶

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

标签云

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