0


Linux小程序 —— 进度条

前言:经过这么多天的学习,想必大家学到了很多Linux知识,今天我们来用Linux来实现我们的第一个小程序 — — 进度条


在这里插入图片描述


本篇主要内容将会实现三个版本的进度条:

  • 简单原理版本
  • 实际工程实践版本
  • 拓展版本

在这里插入图片描述

在实现进度条之前,我们先了解一些之前没提到过的知识,以便我们理解


进度条

    1. 缓冲区的概念
    1. \r&&\n
    1. 进度条
    • 3.1 版本一- 3.2 版本二- 3.3 版本三
    1. 总结拓展

1. 缓冲区的概念

我们先来分析下面几段代码感受一下行缓冲区的存在:

在Linux当中以下代码的运行结果是什么样的?

#include<stdio.h>#include<unistd.h>intmain(){printf("你能看见我嘛\n");sleep(2);return0;}

**这段代码运行结果显而易见:

printf

函数直接打印内容,然后休眠2秒。**

对于大家可能没有什么难度。那如果我们修改一下代码。

#include<stdio.h>#include<unistd.h>intmain(){printf("你能看见我嘛");sleep(2);return0;}

缓冲区的概念

**通过视频我们发现,我仅仅是将

\n

删除了,但是却带来了完全不一样的运行结果:先休眠2秒,然后才是

printf

函数打印内容**

那么为什么会出现这种情况呢? C语言执行代码的逻辑不应该是从上至下执行吗?

  • 按照 C语言执行代码的逻辑printf确实已经运行了,只不过内容没有被显示出来!
  • 内容所在的区域则是在输出缓冲区中!

C/C++语言,会针对标准输出,给我们提供默认的缓冲区

**

fflush

函数可以刷新缓冲区,如果我们想立马显现可以用函数刷新

fflush()

,而

\n

是一种刷新的策略——行刷新,所以

\n

也能立马显现!**


2. \r&&\n

概念:

  • \r: 回车,使光标回到本行首格
  • \n: 换行,使光标移到下一行

光说可能大家不太理解,我们来实操看看:

#include<stdio.h>#include<unistd.h>intmain(){int cnt =10;while(cnt){printf("%d\r", cnt--);fflush(stdout);sleep(1);}return0;}

回车 \r

我们可以看到在输出下一个数之前都让光标先回到本行首格。
但是为什么输出结果和我预想的完全不一样?

在这里插入图片描述

printf("%-2d\r", cnt--);

我们以两位字符进行输出,-则是表示靠左对齐,就可以正常输出了!


3. 进度条

在进行上面的铺垫之后,我们开始编写我们的第一个小程序。我们将用两个源文件和一个头文件,一个申明,一个调用,一个实现

test.c:实现
test.h:申明
main.c:调用

// Makefile:
mytest:test.c main.c
     gcc -o $@ $^.PHONY:clean
clean:
     rm -rf mytest 

3.1 版本一

在版本一中,我们只要简单实现一下基本的功能,得到一个基本框架就足够了。

// process_v1//test.h:申明
pragma once
#include<stdio.h>#include<string.h>#include<unistd.h>// 定义进度条的总长度,因为有'\0'的存在所以设为101#defineSIZE101// 定义进度条的当前进度#defineMAX_RATE100// 进度条的符号#defineSTYLE'#'// 进度条的休眠时间#defineSTIME1000*15voidprocess_v1();.............//test.c:实现#include"test.h"// 旋转光标constchar*str ="|/-\\";// \\:才能表示一个'\'voidprocess_v1(){int rate =0;//初始化进度条全为'\0'char bar[SIZE]={0};//循环打印int num =strlen(str);while(rate <= MAX_RATE){// 进度条的打印格式// -100:先取好[]的范围,然后靠左打印。printf("[%-100s][%d%%][%c]\r", bar, rate, str[rate%num]);// 刷新缓冲区                                                                                                                                   fflush(stdout);// 休眠时长usleep(STIME);// 填充符号
         bar[rate++]= STYLE;}// 刷新printf("\n");}.............//main.c:调用#include"test.h>intmain(){process();return0;}

进度条:版本一

我们的第一代进度条也就完成了,实现了基本的结构框架!而我们的进度条,肯定不能干自己的,一定是和某种任务关联起来的!


3.2 版本二

我们将循环改成内部维护一个简单的静态缓冲区,每次往缓冲区里面增加内容然后刷新缓冲区内容就可以

不能一次将进度条打印完毕,否则不能与场景更好的结合

// process_v2//test.h:申明#pragmaonce#include<stdio.h>#include<string.h>#include<unistd.h>#defineSIZE101#defineMAX_RATE100#defineSTYLE'#'#defineSTIME1000*15typedefvoid(*callback_t)(int);// 回调函数        // 这里我们也可以使用函数指针                                                                                                                                                                                    voidprocess_v2(int);~.............//main.c:调用#include"test.h"#defineTARGET_SIZE1024*1024// 模拟下载软件的大小#defineDSIZE1024*10// 模拟下载的速度//void download()//{//    int target = TARGET_SIZE; // 软件总体积//    int total = 0; // 当前下载的大小// //    while(total < target)//    {//        usleep(STIME); // 用休眠时间,模拟下载时间//        total += DSIZE;//       process_v2(total*100/target);                                                                                                                                                  //    }//    printf("\n");//}// 回调函数voiddownload(callback_t cb){int target = TARGET_SIZE;// 软件总体积int total =0;// 当前下载的大小while(total < target){usleep(STIME);// 用休眠时间,模拟下载时间
        total += DSIZE;int rate = total*100/target;cb(rate);}printf("\n");}intmain(){download(process_v2);return0;}.............//test.c:实现#include"test.h"constchar*str ="|/-\\";voidprocess_v2(int rate){staticchar bar[SIZE]={0};int num =strlen(str);if(rate <= MAX_RATE && rate >=0){printf("[%-100s][%d%%][%c]\r", bar, rate, str[rate%num]);fflush(stdout);
        bar[rate]= STYLE;}if(rate == MAX_RATE){// 重新刷新为0memset(bar,'\0',sizeof(bar));}}

进度条:版本二

我们也能完成进度条的实现,最后我们在优化一下,变成我们的版本三!。


3.3 版本三

因为版本二已经能将进度条完美的呈现了,我们版本三,只是在二的基础上,美化一下,所以只是简单修改一点代码!

在这里插入图片描述

// test.h#defineSTYLE_DEADER'>'#defineSTYLE_BODY'='typedefvoid(*callback_t)(double);

.............// main.c// 我们在下载时,模拟下载中断的状态voiddownload(callback_t cb){int target = TARGET_SIZE;// 软件总体积int total =0;// 当前下载的大小while(total <= target){usleep(STIME);// 用休眠时间,模拟下载时间
        total += DSIZE;double rate = total*100/target;// 我们让下载进度永远维持在50%左右if(rate >50.0){
            total = target/2;}cb(rate);}printf("\n");}.............// test.cif(rate <= MAX_RATE && rate >=0){// 设置cnt是为了在下载终止时,光标依然能变化
    cnt++;
    cnt = cnt > num ?0: cnt;// \033[1;47;30m ... \033[0m 则是更改输出时字体和背景颜色printf("加载中...\033[1;47;30m%-100s\033[0m][%.1lf%%][%c]\r", bar, rate, str[cnt]);fflush(stdout);if(rate < MAX_RATE){
        bar[(int)rate]= STYLE_BODY;
        bar[(int)rate+1]= STYLE_HEADER;}else{
           bar[(int)rate]= STYLE_BODY;}}

进度条:版本三

我们可以发现,我们修改了字体颜色和背景,设置测试了可能遇到的中断情况,光标依旧会变化。当然了进度条还有很多情景,等待着各位开发!


4. 总结拓展

拓展:
关于print带颜格式化输出,我在这里推荐一篇博客,有兴趣的可以去了解一下
print带颜格式化输出


**总结:
本篇我们简单了解了一下缓冲区,以及换行

'\n'

与回车

'\r'

的基本概念,然后由浅入深的介绍了三个版本的进度条,当然了美化方式各位都不一样,都是可以的,我们的Linux第一个小程序就讲到这里**

谢谢大家支持本篇到这里就结束了
在这里插入图片描述

标签: linux 小程序 运维

本文转载自: https://blog.csdn.net/EterNity_TiMe_/article/details/138958638
版权归原作者 Eternity._ 所有, 如有侵权,请联系我们删除。

“Linux小程序 —— 进度条”的评论:

还没有评论