【Linux】-第一个小程序(进度条)

作者:小树苗渴望变成参天大树
作者宣言:认真写好每一篇博客
作者gitee:gitee
作者专栏:C语言,数据结构初阶,Linux,C++ 动态规划算法
【Linux】-第一个小程序(进度条)_第1张图片

如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧!

文章目录

  • 前言
  • 一、知识铺垫
    • 1.1回车换行
    • 1.2行缓冲区
    • 1.3倒计时
  • 二、进度条
    • 2.1基础进度条
    • 2.2进阶进度条
  • 三、总结


前言

大家好久不见,已经快一个月没有更新Linux相关的知识了,希望大家还没有忘记前面学过的知识,不记得可以看看我前面写的博客,可以快速帮大家进行回忆,今天我们讲讲一个新的知识,把我们前面说到的make进行联系起来,再讲小程序进度条之前,我还有两个知识铺垫,不然大家不好理解,话不多说,我们开始进入正文


一、知识铺垫

再讲解进度条之前,我们必须了解这两个概念,一个是回车换行,一个是行缓冲区

1.1回车换行

对于回车换行其实是两个概念,一个是回车,一个是换行,换行是光标换到下一行,并不会到文本的开头,回车使光标回到当前行的开始,那在我们语言的层面是怎么做到对文本进行换行和回车的,我们平时说到 \n其实就是换行的意思的,但是语言的本身把他解释成回车换行,\r是回车的意思的,回车换行其实就是先换行再进行回车,我们来看看老式的键盘
【Linux】-第一个小程序(进度条)_第2张图片
这个标志就很形象,为什么要讲解这个知识点,原因是为了更好的引出下面这个要铺垫的知识点

1.2行缓冲区

再我们的C语言中,我们要行缓冲区,这是个什么,为什么要有这个,再我们运行程序的时候,我们会在屏幕上看到显示的内容,这些都是由字符组成的,那我们的C语言不是一个字符一个字符的显示再屏幕上,这样觉得消耗太大了,所以我们有了行缓冲区的概念,就是程序运行时的一块内存,把数据先放到这个内存里面,等到这个小内存满了,就直接一起全部给刷新出来,为什么又叫行缓冲区,就是当一行满了,就一起刷新出来,只有遇到\n或者scanf或者fflush这样的函数就会提前进行刷新,程序结束后,最终也会将数据进行刷新出来。

所以我们来看一个例子:

#include 
#include
int main()
{
 printf("hello Makefile!\n");
 sleep(3);
 return 0;
}

【Linux】-第一个小程序(进度条)_第3张图片
再来看这个代码:

#include 
#include
int main()
{
 printf("hello Makefile!");//1
 sleep(3);//2
 return 0;
}

【Linux】-第一个小程序(进度条)_第4张图片
大家看到这个结果大概率会认为先执行了2代码,再执行1代码,但是事实却不是这个样子的,我们C语言的代码都是自上往下进行执行的,除非遇到跳转,循环之类的,对于上面的代码的肯定是先执行的打印函数,再执行休眠函数,那为什么不是先打印出来呢??原因就是,打印的数据再缓冲区里面,然后开始执行了2代码,最后程序结束了,就会一起刷新出来,最后从显示出来。

我们想必须提前刷新出来,还有一种方法就是使用fflush函数,我们查看一下手册【Linux】-第一个小程序(进度条)_第5张图片
再我们c语言会默认打开三个流,这个再C语言专栏的文件操作讲过,一个是输入流stdin,一个是输出流stdout,一个是错误流stderr,而fflush的参数就是传流进出,这里是将数据输出,所以使用输出流

代码修改:

#include 
#include
int main()
{
 printf("hello Makefile!");
 fflush(stdout);
 sleep(3);
 return 0;
}

【Linux】-第一个小程序(进度条)_第6张图片
大家看到达到我们想要的效果了吧。

1.3倒计时

结合上面讲的两个知识点,进行编写一个倒计时。

  1 #include"processBar.h"
  2 int main()
  3 
  4 {
  5     int cnt=9;
  6     while(cnt>=0)
  7     {
  8         printf("%d",cnt);
  9         fflush(stdout); //不加会显示不出来,最后会一起显示出来                                                                                                                                               
 10         sleep(1);
 11         cnt--;
 12     }
 13     return 0;
 14 }

不加:
【Linux】-第一个小程序(进度条)_第7张图片
加:
【Linux】-第一个小程序(进度条)_第8张图片

显然这两种都不是我们想要的倒计时,我们看看有一个特点,我们每输出一个时间光标就往后面跑一个字符,所以想要把之前的字符覆盖,就要是光标一直再开头的位置,所以我们再打印的时候加一个 \r

+\r
【Linux】-第一个小程序(进度条)_第9张图片
这才是我们想要的倒计时,但是这个程序还有一个小毛病,但从大于9开始倒计时就会出现问题,我们需要进行打印格式的调整

会出现下面的情况:

【Linux】-第一个小程序(进度条)_第10张图片
解决方法:(以%-2d的形式进行打印就可以了)
【Linux】-第一个小程序(进度条)_第11张图片

到这里我们的知识铺垫到此结束,接下来开始正式讲解进度条的实现

二、进度条

我们最终是要将我们的进度条模拟实现成多软件一起下载的场景,如下:
【Linux】-第一个小程序(进度条)_第12张图片

此次进度条的模拟实现,我打算使用多文件的方式,使用自动化构建来编写,我们开始做一些前期工作【Linux】-第一个小程序(进度条)_第13张图片
我们准备工作做好之后,我们开始来实现进度条代码吧

2.1基础进度条

设计思想: 在实现对多软件的模拟进度条下载,我们必须先弄清楚一个普通的进度条是怎么实现的吧。我们就需要使用到\r的特性,\r是回车的意思,将光标回到当前行开始的地方,我们采取的是先打印一个字符,然后再增加一个字符进行覆盖打印,如果是换行打印,就类似于一个直角三角形,我们来看代码实例:

  1. 错误示范
    【Linux】-第一个小程序(进度条)_第14张图片
    这个显然不是我们想要的效果,我们达到我们想要的推进式打印,但是想要打印在同一行,这时候就需要使用\r使光标变到第一行,然后一次一次的覆盖打印,但是要记得刷新。

  2. 正确操作
    【Linux】-第一个小程序(进度条)_第15张图片
    这个就符合我们想要的进度条了,但是这个进度条和我们一开始想要的还是有差别

  3. 将进度条放在一个框框里面,并且显示进度,这个需要了解C语言的打印格式,C语言默认是右对齐,我们想要每次打印从左往右,就需要采取左对齐,再框框里面预留100个位置,因为一次是增加一个字符,我们来看代码:
    【Linux】-第一个小程序(进度条)_第16张图片

  4. 等待旋转标志
    这个是告诉用户进度条再运行,给个提示,使用字符 **|/-\**循环打印来模拟实现再旋转的场景,看代码:
    【Linux】-第一个小程序(进度条)_第17张图片
    我们的第一代进度条就算是完成了,我们再来完善一下,使他变得可控一些
    【Linux】-第一个小程序(进度条)_第18张图片
    代码:

  1 #include"processbar.h"
  2 void processbar()
  3 {
  4     char bar[NUM]={0};
  5     int cnt=0;
  6     const char*label="|/-\\";
  7     int len=strlen(label);
  8     while(cnt<=100)
  9     {
 10         printf("[%-100s][%d%%][%c]\r",bar,cnt,label[cnt%len]);
 11         fflush(stdout);
 12         usleep(50000);//控制进度条的时间                                                                                                                               
 13         bar[cnt++]=STYLE;
 14     }
 15     printf("\n");
 16 }

2.2进阶进度条

我们要是想完成这个进阶进度条,就不能把循环放进一个函数里面,这样是不可控的,我们要专门写一个下载函数,来进行软件的下载,把下载的进度单独设置成一个函数,什么叫下载的进度,下面这就叫下载的进度

【Linux】-第一个小程序(进度条)_第19张图片
我们来修改代码:

 1 #include"processbar.h"
  2 
  3 //下载函数
  4 void download(int tatol,int internetspeep)//传软件总大小和下载速度
  5 {
  6     initbar();
  7     int cur=0;//从0MB开始下载
  8     while(cur<=tatol)
  9     {
 10         processbar(cur*100/tatol,tatol,internetspeep);//乘100是因为传进去里面有百分比,传当前进度,总大小和下载速度
 11         cur+=internetspeep;//internetspeepMB/s的速度下载
 12         usleep(1000000);
 13     }
 14     printf("\n");
 15 }
 16 //进度函数
 17 char bar[NUM]={0};//设置成全局的,因为再下载函数里面要频繁调用进度函数,而进度是一直推进的,放在进度函数里面会导致调用依次之后就会被销毁
 18 void initbar()//每次任务下载的之前都要初始化一下
 19 {
 20     memset(bar,'\0',sizeof(bar));
 21 }
 22 void processbar(int rate,int tatol,int internetspeep)//传当前进度进来,就是已经下载的大小占总大小的多少
 23 {
 24     const char*label="|/-\\";
 25     int len=strlen(label);                                                                                                                                             
 26     printf("[%-100s][%d%%][%c][%s%d%s]\r",bar,rate,label[rate%len],"已经下载了",tatol*rate/100,"MB");
 27     fflush(stdout);
 28     int count=internetspeep*100/tatol;
 29     while(count--)//每次进度条增加几条字符,按照下载速度占总大小的百分比老算
 30     {
 31        bar[rate++]=STYLE;
 32     }
 33 }

【Linux】-第一个小程序(进度条)_第20张图片
我们来看运行结果:
【Linux】-第一个小程序(进度条)_第21张图片


这样已经很符合我们平时下载的进度条了,但是我还想再优化一下时进度条好看一些---------->这样的形式
代码优化:【Linux】-第一个小程序(进度条)_第22张图片

【Linux】-第一个小程序(进度条)_第23张图片
颜色优化:(https://blog.csdn.net/wuquan_1230/article/details/106077560)参考这篇博客
代码:
【Linux】-第一个小程序(进度条)_第24张图片

【Linux】-第一个小程序(进度条)_第25张图片
这就实现了一个非常好看的进度条

三、总结

今天大家实现了Linux上的第一个小程序,进度条,希望大家下来可以自己去实现一下,还是比较好玩的,也可以修改成自己风格的进度条,我们今天的知识就讲解到这里了,下篇再见

你可能感兴趣的:(Linux系统编程,linux,小程序,运维)