> 🍃 本系列为Linux的内容,如果感兴趣,欢迎订阅🚩
> 🎊个人主页:【小编的个人主页】
>小编将在这里分享学习Linux的心路历程✨和知识分享🔍
>如果本篇文章有问题,还请多多包涵!🙏
> 🎀 🎉欢迎大家点赞👍收藏⭐文章
> ✌️ 🤞 🤟 🤘 🤙 👈 👉 👆 🖕 👇 ☝️ 👍
目录
🐼前言
我们将使用LInux中基础指令,使用工具vim编写一个进度条程序。通过自已编写的Makefile,使用指令make形成可执行程序,使用指令make clean清理文件
进度条效果演示:
进度条效果演示
🐼回车pk换行,缓存区刷新机制
回车换行是一个概念吗?
答案显然不是,回车是指光标回到这一行的初始位置(\r就是回车的转义字符),换行是直接切换到下一行,而不回到这一行的初始位置,而我们平时C语言中使用的"\n"默认是回车+换行。
那这有什么用呢?我们来观察一个现象:
首先我们创建一个code.c文件来观察,其内容是:
形成可执行程序
运行结果,我们发现,hello world先被打印到显示屏上,然后过了一秒,程序完成,符合我们的预期。
我们这次不加"\n"试试:
现象:发现,屏幕中先过了一秒,然后最后显示出来hello world
那我们这次只加回车"\r"试试:
现象:发现hello world竟然被吞掉了,什么都不打印,这是为什么????hello world 去哪了??
其实在睡眠期间,hello world在缓存区中,而"\n"作为一种刷新机制,可以直接刷新到显示屏文件中,所以我们看到了hello world。第二种,在程序结束后,将缓存区中的内容拷贝到显示屏文件中,所以我们也能看到,第三种,加了"\r"回车,我们看不到的原因是因为,光标回到这一行的开始位置,程序结束,将光标前的内容刷新,没有内容,所以什么都没有。
总结一下刷新机制:
1:如果\n或者\r\n,会使\n之前的内容,全部刷新到显示器上
2:程序结束,历史数据,会被刷新到显示屏上
那对于第三种情况,如果我们想强行刷新到显示屏上可以使用fflush函数进行刷新(即将缓存区的内容刷新到显示屏中):
修改完再打印一下code.c
此时即是回车,也将内容刷新到显示屏上。
🐼小demo
那既然有了以上理论,我们可以实现一个简易版的计时器,回车到起始位置,进行刷新覆盖.
#include<stdio.h> #include<unistd.h> int main() { int n = 10; while(n) { printf("%-2d\r",n); fflush(stdout); n--; sleep(1); } printf("\n"); return 0; }
每次打印完,回车到起始位置,将内容刷新到显示屏上,光标又回到了行开始位置。让我们有了一种计时器倒计时的感觉。回车的目的就是将光标重新回到起始位置。
🐼进度条编写
下面我们实现一个进度条,目标有三个:
1:能不断加载进度条
2:能显示百分比
3:加载图标能不能转动,表示加载中~
下面我们先根据以上要求实现一个简易版:
我们通过"process.h","process.c","main.c"三个文件进行实现:
让我们的进度条先跑起来:
"process.c"逻辑
#include"process.h" #define LENGTH 101 #define LABLE '#' void process() { //定义缓存区 static char bar[LENGTH]; memset(bar,0,sizeof(bar)); //定义光标 const static char* str = "/|\\-"; int len = strlen(str); int cnt = 0; while(cnt<LENGTH) { printf("[%-100s][%d%%][%c]\r",bar,cnt,str[cnt%len]); fflush(stdout); bar[cnt++] = LABLE; usleep(20000); } printf("\n"); }
我们通过让cnt不断增长,我们默认进度条的长度最多为100字'#',直到填充满,每次填充,我们都进行刷新,并让光标回到初始位置,为下一次刷新做准备,加载图标通过通过取模运算每次更新。
verson1进度条演示:
verson1
可是,这样,是不符合实际情况的。原因:
我们的下载速度都是与下载包大小和网速有关的,所以进度条增加速度我们需要关心。
即进度条不能直接更新完,要根据具体进度进行刷新。
我们更新一下下载逻辑:
通过下载安装包和下载速度实时更新,下载一次每次都刷新进度条,只要没下载完,就一直下载。
"main.c"
#include"process.h" //直接替换 #define TOTAL 1024.0 #define SPEED 1.0 //检查对比一次,并加几组,看看下载速度和网速 void DownLoad(double total,double speed) { double current = 0; while(current<=total) { FlushProcess(current,total); usleep(2200); current+=speed; } } int main() { printf("下载中\n"); DownLoad(TOTAL,SPEED); DownLoad(1024.0,1.0); DownLoad(512.0,2.0); DownLoad(800.0,4.0); DownLoad(2000.0,2.0); DownLoad(10240.0,10.0); printf("下载完成>^o<^\n"); return 0 ; }
"process.c"
#include"process.h" #define LENGTH 101 #define LABLE '#' void FlushProcess(double current,double target) { //更新出当前进度 double rate = (current/target)*100.0;//200-1000 //整数个进度递增,刷新一个# int cnt = (int)rate; //定义光标 const static char* sysb = "/|\\-"; int len = strlen(sysb); static int index = 0; //缓存区 static char bar[LENGTH]; memset(bar,0,sizeof(bar)); for(int i=0;i<cnt;i++) { bar[i] = LABLE; } printf("[%-100s][%.1lf%%][%c]\r",bar,rate,sysb[index++]); fflush(stdout); index%=len; if(rate>=100.0) printf("\n"); fflush(stdout); }
"process.h"
#include<stdio.h> #include<unistd.h> #include<string.h> void FlushProcess(double current,double target);
最后,看一下我们做出来的效果:
verson2:
感谢你耐心地阅读到这里,你的支持是我不断前行的最大动力。如果你觉得这篇文章对你有所启发,哪怕只是一点点,那就请不吝点赞👍,收藏⭐️,关注🚩吧!你的每一个点赞都是对我最大的鼓励,每一次收藏都是对我努力的认可,每一次关注都是对我持续创作的鞭策。希望我的文字能为你带来更多的价值,也希望我们能在这个充满知识与灵感的旅程中,共同成长,一起进步。如果本篇文章有错误,还请大佬多多指正,再次感谢你的陪伴,期待与你在未来的文章中再次相遇!⛅️🌈 ☀️