教育培训门户网站模板下载,山西中考考生网上服务平台,电子菜单制作app,销售平台有哪些【Linux系统】—— 简易进度条的实现 1 回车和换行2 缓冲区3 进度条的准备代码4 第一版进度条5 第二版进度条 1 回车和换行 先问大家一个问题#xff1a;回车换行是什么#xff0c;或者说回车和换行是同一个概念吗#xff1f; 可能大家对回车换行有一定的误解#xff0… 【Linux系统】—— 简易进度条的实现 1 回车和换行2 缓冲区3 进度条的准备代码4 第一版进度条5 第二版进度条 1 回车和换行 先问大家一个问题回车换行是什么或者说回车和换行是同一个概念吗 可能大家对回车换行有一定的误解本文在这里讲解一下 假设我们是在写小作文 换行将笔尖换到下一格即移动到下一行。回车将笔尖移动到本行的开头。 在计算机中换行符为「\n」回车符为 「\r」我们往往用「\r\n」来整体表示回车换行。 但之前写 C语言 时我们只用「\n」也能同时达到回车和换行的效果这是在语言层面上将 \n 解析成 \r\n
2 缓冲区 下面我们非常粗略的了解一下缓冲区的概念
先来段测试代码
#include stdio.h
#include unistd.hint main()
{printf(Hello Linux!\n);sleep(3);return 0;
}注 sleep() 函数的头文件为unistd.h 一切正常 我们将 printf 中的「\n」去掉试试
#include stdio.h
#include unistd.hint main()
{printf(Hello Linux!);sleep(3);return 0;
}结果好像和我们想的有点不太一样。 解释上面原因前先问大家一个问题上述代码是先执行 printf还是先执行sleep 按结果来看应该是先执行 sleep再执行printf 但事实恰恰相反是先执行的 printf。在初学C语言时我们知道一个程序有几种控制流循环、判断、顺序。我们对应的程序在执行时永远都是从前往后执行的 当程序执行到 sleep 语句时它一定是把 printf 执行完了。可显示器上并没有显示那在休眠的 3 秒期间字符串 “Hello Linux” 在哪呢在缓冲区里 简单理解一下在内存中有一块内存块叫缓冲区先将字符串临时存放在缓冲区里。缓冲区向显示器输出是行刷新也就是说它遇到 \n 自动将缓冲区的内容刷新出去如果没遇到就一直在缓冲区中呆着直到程序退出时再自动刷新缓冲区我们才能看到打印出的字符串。 如果想让不带 ‘/n’ 的字符串立即刷新可以用 fflush 函数
#include stdio.h
#include unistd.hint main()
{printf(Hello Linux!);fflush(stdout);sleep(3);return 0;
}3 进度条的准备代码 我们先不急着写进度条先写几段测试代码 先来实现一个倒计时
int main()
{int i 9;while(i 0){ printf(%d\n, i); --i;} return 0;
}现在它是换行进行打印但我们想让它在同一个位置打印。这时我们可以运用前面学习到的回车符 「\r」
int main()
{int i 9;while(i 0){ printf(%d\r, i); --i;sleep(1);} return 0;
}为什么它一直不显示呢而且最后程序结束了命令行覆盖了什么都没有 这是因为数据一直在缓冲区没有刷新出来而最后程序运行结束刷新缓冲区了因为回车符命令行从头开始写将数据覆盖了。 我们手动刷新缓冲区并且为了不让命令行覆盖数据我们单独进行换行
int main()
{int i 9;while(i 0){ printf(%d\r, i); fflush(stdout);--i;sleep(1);} printf(\n);return 0;
}现在我们写的代码就可以进行倒计时了……了吗 还没有如果我们改成从 10 开始倒计时会怎样 又出问题了。 讲个小知识点显示 当我们向显示器中输出 12345 这个数时显示器上本质上是输出 12345 这个数字还是 ‘1’ ‘2’ ‘3’ ‘4’ ‘5’ 这 5 个字符呢 答案是后者。显示器是字符设备它只认字符 这也解释了为什么我们 printf 要格式化输出。比如我们输出一个 int aprintf 内部将其由整数转成字符串再用类似 putc 的接口一个一个字符输出到显示器上 怎么解决上述问题呢很简单将输出的显示的位宽改为 2 即可
int main()
{int i 10; while(i 0){ printf(%-2d\r, i); fflush(stdout);--i;sleep(1);} printf(\n);return 0;
} 4 第一版进度条 我们想写一个怎么样的进度条 一对 [ ] 括起100个空字符每加载 1% 就有一个 ‘#’ 替换一空字符并在后面显示下载进度和转圈圈表示软件一直在下载 首先创建多文件 再写 makefile对 makefile 有困惑的小伙伴可移步【Linux系统】—— make/makefile 基本框架如下 process.c 代码如下 如果大家觉得休眠 1 秒时间太长这里给大家再介绍一个新的休眠函数usleep usleep 函数的休眠时间是以微妙为单位的头文件同样是unistd.h 效果如下 现在我们还需要加上百分比和旋转光标。旋转光标是用来告诉用户该程序一直在下载中。 百分比的实现很简单这里就不单独介绍了需要注意的是打印 ‘%’要输入 ‘%%’ 表示取其字面值 我们简单介绍一下简易光标如何实现 其实旋转光标很简单只需要 | / - \ 不断循环打印即可因为 \ 是特殊字符我们输入 \\ 表示取字面值 至此我们就完成了第一版进度条代码如下
#include process.h
#include string.h
#include unistd.h#define NUM 101
#define STYLE #void process_v1()
{char buffer[NUM];memset(buffer, 0, sizeof(buffer));const char* lable |/-\\;int len strlen(lable);int cnt 0;while(cnt 100){ printf([%-100s][%2d%%][%c]\r, buffer, cnt, lable[cnt % len]);fflush(stdout);buffer[cnt] STYLE;cnt;usleep(100000);} printf(\n);
}效果展示 5 第二版进度条 第一版本的进度条看起来像模像样的其实它根本无法使用 因为第一版本的进度条和下载的软件是各跑各的可能软件值下载了 1% 但我们的进度条已经跑完了而真实的进度条是要反应真实下载进度的。 一个进度条一定要结合具体的场景边下载边更新进度条。 我们定义变量 total 来表示要下载的总大小speed 为下载的速度当然实际的下载速度是浮动的但这里为方便我们将其固定下来current 表示当前已下载量。当然真正的下载是要从网络中获取数据的这点我们还没学就用休眠时间来替代
// main.c
#include process.h
#include unistd.h
#include stdio.hdouble total 1024;
double speed 1.0;void DownLoad()
{double current 0;while(current total){ //下载代码usleep(3000);//充当下载数据current speed;} printf(download %lfMB Done\n, current);
}int main()
{DownLoad();return 0;
}现在的情况是我们不知道他正在下载因此我们需要引入进度条。 我们重新定义一个 FlushProcess()函数FlushProcess()函数 的作用是根据当前的下载进度来打印进度条
部分代码如下
void FlushProcess(double total, double current)
{char buffer[NUM];memset(buffer, 0, sizeof(buffer));const char* lable |/-\\;int len strlen(lable);static int cnt 0;//不需要自己循环,填充#int num (int)(current * 100 / total);int i 0;for(; i num; i){ buffer[i] STYLE;} double rate current / total;cnt % len;printf([%-100s][%.lf%%][%c]\r, buffer, rate * 100, lable[cnt]);cnt;fflush(stdout);
}void DownLoad()
{double current 0;while(current total){ //调用FlushProcess函数不断打印进度条FlushProcess(total, current);//下载代码usleep(3000);//充当下载数据current speed;} printf(\ndownload %.2lfMB Done\n, current);
}int main()
{DownLoad();return 0;
}效果演示 但是上述代码还有一点小问题现在是下载需要进度条如果以后是上传呢上传也需要有对应的进度条。但此时的进度条函数 FlushProcess() 是硬加载在下载函数 DownLoad() 中的如果是上传需要的函数是 UpLoad()那是不是在 UpLoad()函数中也要加载一份进度条 FlushProcess() 函数呢这样做是不是太麻烦了 为了解决这个问题我们可以使用函数指针
完整代码
//process.h
#pragma one
#include stdio.hvoid FlushProcess(double total, double current);//process.c
#include process.h
#include string.h
#include unistd.h#define NUM 101
#define STYLE #void FlushProcess(double total, double current)
{char buffer[NUM];memset(buffer, 0, sizeof(buffer));const char* lable |/-\\;int len strlen(lable);static int cnt 0;//不需要自己循环,填充#int num (int)(current * 100 / total);int i 0;for(; i num; i){ buffer[i] STYLE;} double rate current / total;cnt % len;printf([%-100s][%.lf%%][%c]\r, buffer, rate * 100, lable[cnt]);cnt;fflush(stdout);
}//main.c
include process.h
#include unistd.h
#include stdio.htypedef void(*callback_t)(double total, double current);double total 1024;
double speed 1.0;void DownLoad(callback_t cb)
{double current 0;while(current total){ cb(total, current);//下载代码usleep(3000);//充当下载数据current speed;} printf(\ndownload %.2lfMB Done\n, current);
}int main()
{DownLoad(FlushProcess);return 0;
} 好啦本期关于 进度条 的知识就介绍到这里啦希望本期博客能对你有所帮助。同时如果有错误的地方请多多指正让我们在 Linux 的学习路上一起进步