【Linux】-----进度条小程序
创始人
2024-11-16 14:05:00
0

目录

前言

基本知识

Ⅰ、回车和换行

Ⅱ、缓冲区

 两个有意思的现象

简单定义

刷新缓冲区

简易倒计时程序

进度条代码

多文件下makefile写法

一代(无任何场景)

procs1.h代码

procs1.c代码

主函数main1.c

一代运行结果:

二代 (搭配下载场景)

procs2.c代码

procs2.h代码

主函数main2.c 代码

二代结果显示:


前言

前面我们已经学会基本的Linux指令和工具,那么现在来搞个好玩的东西-进度条(简单版本)!!!

基本知识

Ⅰ、回车和换行

首先得明确,回车和换行对于我们而言就是一个简单的动作,可是对于机器来说这是两个独立的动作。

  • 换行

 换行是从末尾位置竖直向下移动一行,此时光标的位置是在下一行的末尾。

  • 回车

 回车是将光标移动到最左侧,也就是文段最开头的位置!

键盘上的回车键是先向下再向左的,对应的就是先换行再回车的两个动作!!

在C语言中,\n是表示回车换行同时,\r仅仅是回车。

Ⅱ、缓冲区

 两个有意思的现象

 ①有‘\n’

代码:

现象:

可以看到,执行这个程序时,先在屏幕上打印对应字符串,休眠3秒后结束程序!

②无‘\n’

代码:

现象:

可以看到这个现象和有‘\n’的不一样,没有'\n'开始运行时并没有打印字符串,而是休眠了3秒,退出程序的同时字符串一起显示出来。。

 对于无‘\n’的现象,我们需要明确一点,程序并不是先休眠了3秒才显示字符串,通俗点来说就是不是先执行sleep函数才去执行printf函数,同样也是先执行printf函数才去执行的sleep函数,因为程序是从上往下依次执行的。那么在这段休眠时间里字符串在哪?被放在了缓冲区里

简单定义

目前我们仅需知道缓冲区实际上就是一块内存空间,对于上面的字符串,就是被保存在这样的一块内存空间里,当程序运行结束时,会自动的刷新缓冲区里的内容到显示器上,所以无‘\n’才能看到上述的现象。

刷新缓冲区

①加上‘\n’,立即刷新

②等待缓冲区满或者程序结束,自动刷新

③强制刷新

怎么强制?

实际上C语言提供了一个的函数--fflush,这个函数就是用于强制刷新缓冲区的。。

这里的文件流后面的文章有详细讲解,现在我们只需要知道程序在运行时默认会打开三种流

  • 标准输入,stdin
  • 标准输出,stdout
  • 标准错误,stderr

我们的显示器就是标准输出文件,Linux下一切皆文件!所以可以采用该函数强制刷新到对应的文件流上。

演示:

 代码:

现象:

可以看到,即使程序没有‘\n’,也能直接显示字符串内容!!

有了上面的知识可以先来实现一个简单的倒计时程序

简易倒计时程序

 原理:实际就是对同一个位置进行覆盖进而实现一个动态的效果。

每当显示一个数字之后就将光标挪动至最前面(回车),休眠,然后再显示下一个数字。回车配休眠需要强制刷新缓冲区。

代码:

1 #include    2 #include    3    4 int main()   5 {   6   int cnt=10;   7    8   while(cnt>=0)   9   {  10     printf("倒计时:%2d\r",cnt);  11   12     fflush(stdout);//强制刷新到屏幕  13     sleep(1);                                                                                                                                                             14     cnt--;  15   }  16   return 0;  17 } 

注意:为什么用%2d,是因为数字显示在屏幕上时,实际上是字符串的形式,相当于10是两个字符的字符串,需要覆盖两个字符。当然,大家感兴趣把2去掉看看! 

结果如下:

进度条代码

这里采用多文件的形式去实现的,为了更加方便的去管理代码。

多文件下makefile写法

一代(无任何场景)

procs1.h代码

主要是头文件的包含以及函数的声明!

#pragma once                                                                                                 #include                                                                  #include                                                                      #include                                                                                                                                                                                                                                                                          void processbar1();     

procs1.c代码

主功能实现

代码如下:

#include "procs.h"  #define Length 101 //进度条长度 #define Style '|' //进度条样式 const char* lab="|/-\\";//加载旋转光标 void processbar1() {   char bar[Length];//字符数组   memset(bar,'\0',sizeof(bar));//初始化为\0   int cnt=0;   while(cnt<=100)   {      printf("[%-100s][%3d%%][%c]\r",bar,cnt,lab[cnt%strlen(lab)]);//\r为了完成覆盖                                                                                             fflush(stdout); //强制刷新      bar[cnt++]=Style;//字符追加至数组中      usleep(100000);   }    printf("\n");  } 

代码解释:

①根据上述的效果图,进度条实际上是放在一个数组的中,所以定义一个长度为101的字符数组。数组按字节全部初始化为'\0'!

②因为要带来动态的效果所以运用上面提到的倒计时程序类似。回车('\r')配延时,强制刷新缓冲区

③%-100s:表示左对齐

④%3d%%:最后的双百分号,是为了取字面值%,以实现100%的效果。因为单独一个%在C语言中有着特殊含义。

const char* lab:字符串,同样最后的”\\“,也是为了取字面值\,防止转义,单独的\在C语言有着特殊含义。

⑥lab[cnt%strlen(lab)]:取模操作是为了防止数组越界!

主函数main1.c

调用函数即可。

 

一代运行结果:

二代 (搭配下载场景)

进度条不可能单独存在,一般常见的场景就是下载这一场景,会根据网络带宽,文件大小等其他的要素来决定下载进度,当然哦这里只是简单的模拟一下,没有涉及从网络获取数据等其他相关知识。

procs2.c代码

这里的改进主要是函数头包含了文件的总大小以及当前的下载进度。根据进度打印进度条!

#include "procs.h"  #define Length 101 //进度条长度 #define Style '|' //进度条样式 const char* lab="|/-\\";//加载旋转标志 void processbar2(double total,double current) {                                                                                                                                                                          char bar[Length];   memset(bar,'\0',sizeof(bar));//初始化为\0   int len=strlen(lab);   int cnt=0;   double rate=(current*100.0)/total;//计算比率   int load_top=(int)rate;   while(cnt<=load_top)   {      bar[cnt++]=Style;//字符追加至数组中   }     printf("[%-100s][%.1lf%%][%c]\r",bar,rate,lab[cnt%len]);//\r为了完成覆盖     fflush(stdout); //强制刷新 } 

解释一下:

①因为主函数的下载功能是一个循环,会不断的调用该功能函数,每次的下载进度都不一样,因此需要计算每次的比率,再根据比率去打印进度条。。

②这里和一代的不同就是循环体,这里是先将字符一次性放进数组中,最后在一起刷新出来。如果不这样的话每次都会显示从0开始打印,并不是我们想看到的结果。。不信,你可以试试按照一代的写法。。

procs2.h代码

#pragma once   #include  #include  #include  typedef void(*Call_back)(double,double);//定义函数指针类型,为了方便回调                                                                                                     void processbar2(double total,double current); 

注意:这里声明了一个Call_back函数指针类型目的就是实现函数回调。因为未来可能还有更多版本的进度条功能代码, 采用函数指针的方式,只需要传入对应的函数名,就会去调用对应的功能代码。

主函数main2.c 代码

#include "procs.h"                                                                                                                           double bandwith=1024*1024*1.0;//下载速度1MB/s                                                                                               void download(double filesize,Call_back cb)//函数指针做参数                          {                                                                          double cnt=0.0;                                                          printf("download begin....,bandwith is:%.1lf\n",bandwith);               while(cnt<=filesize)                                                     {                                                                          cb(filesize,cnt);                                                        usleep(100000);                                                          cnt+=bandwith;                                                         }                                                                         printf("\ndownload finishi......,filesize is:%.1lf\n",filesize);          printf("\n");                                                        }                                                                      int main()                                                             {                                                                         download(50.0*1024*1024,processbar2);//50MB                             download(10.0*1024*1024,processbar2);//10MB                            download(100.0*1024*1024,processbar2);//100MB                                                                                                                             return 0; } 

如代码,下载功能存在一个函数指针类型的参数,只需传入函数名(函数地址),就能找到对应函数的功能实现,效率极高也十分的巧妙。

二代结果显示:

可以看到,进度条会根据文件大小的不同,下载的速度也不一样,同一带宽情况下,文件越大,那必然越慢,如上图的10MB比100MB快多了。。

二代的场景更加贴近实际哦!!


 好了,今天的分享就到这里,如果对你有帮助,欢迎三连!!!

相关内容

热门资讯

透视中牌率!pokemmo脚本... 透视中牌率!pokemmo脚本辅助器,智星德州插件,玩家教程(有挂解密);1、游戏颠覆性的策略玩法,...
透视辅助器!we-poker靠... 透视辅助器!we-poker靠谱吗,(WePoKer)切实是真的有挂(透视)免费透视脚本(有挂规律)...
透视辅助!wpk俱乐部是做什么... 透视辅助!wpk俱乐部是做什么的,(wpK)一直真的是有挂(透视)刷入池率脚本(有挂秘笈)1、很好的...
透视规律!德扑圈透视, (德普... 透视规律!德扑圈透视, (德普之星)好像存在有挂(透视)透视辅助软件(有挂脚本)1、不需要AI权限,...
透视透视脚本!购买wepoke... 透视透视脚本!购买wepoker模拟器,(wepoker)好像是真的有挂(透视)私局代打(有挂脚本)...
透视安装!佛手在线是不是有挂,... 透视安装!佛手在线是不是有挂,德州局透视脚本免费版下载手机版,新版2025教程(有挂解说)1、下载好...
透视透视!德普之星透视辅助软件... 透视透视!德普之星透视辅助软件是真的吗, (德普之星)都是真的有挂(透视)透视(有挂插件)1、完成德...
透视辅助!wpk作弊是真的吗,... 透视辅助!wpk作弊是真的吗,(wPK)确实是真的有挂(透视)作弊(有挂秘籍)在进入wpk作弊是真的...
透视下载!wepoker有辅助... 透视下载!wepoker有辅助器吗,(WEPOKER)真是是有挂(透视)辅助器激活码(有挂插件)1、...
透视游戏!德州辅助工具到底怎么... 透视游戏!德州辅助工具到底怎么样,拱趴大菠萝有挂吗,力荐教程(有挂工具);一、德州辅助工具到底怎么样...