0


【Linux】实现进度条小程序

个人主页 : zxctscl
如有转载请先通知

文章目录

1. 前言

在之前已经了解了 【Linux】vim的使用和 【Linux】编译器-gcc/g++使用还有 【Linux】自动化构建工具-make/Makefile,有了这些工具,这次来实现一个进度条小程序。

2. 回车和换行

换行:是换到新的一行。
回车:是回到最开始。

举个例子:在格子里面写字的时候,第一行写完,要到第二行,此时到的第二行的结尾,这个叫换行。而从第二行结尾回到第二行开头是回车。
也可以先回车到第一行的开始,再换行到第二行。
在这里插入图片描述
回车和换行是两个动作。

在老式键盘上面就很明显,而现在的键盘为了省空间就不这样了:
在这里插入图片描述

平时在C语言上用到的“\n”叫回车换行,既回车,又换行。
如果想让**只回车就用到

"\r"

**。
有的代码用

"\r\n"

表示回车换行,如果在

"\r"

"\n"

同时存在时,

"\n"

只是换行。

在老式打字机上面就会有下面这样的拨片,当打完一行之后,得手动把它往回拨,一拨纸就往上走(换行),写入位置就往左走,对应就是回车。

在这里插入图片描述

3. 缓冲区

在代码里面把

"\n"

去掉:
在这里插入图片描述
在编译过程中就会发现,再休眠3秒的时候这个程序并没有输出,而是当程序结束的时候程序才输出。
在这里插入图片描述

"\n"

消息就直接显示出来,然后再sleep。
不加

"\n"

这个字符串打印就没有显示出来,先sleep,再到程序退出的时候才显示这个字符串。
在这里插入图片描述

那么在不加

"\n"

那么

printf

sleep

哪个先运行呢?
C语言在执行代码时候,默认从上往下执行,这个叫顺序结构。

printf

只是没有把数据在显示器上显示出来,并不是没有执行。只是在

sleep

期间这个字符串没有显示出来而已。

那么在

sleep

期间字符串在哪里呢?
它被保存到缓冲区里面。它就是一块内存空间。

printf

的时候,把字符串拷贝到缓冲区里面,然后定期把数据刷新到显示器上面,此时就能看到这个字符串了。
不带

"\n"

的时候,字符串就在缓冲区里,当

return 0

时,程序结束时,一般要自动冲刷缓冲区。

想要在程序结束之前就刷新缓冲区,有3种方式:
**1.

"\n"

直接就把缓冲区数据就刷出来了。包含

"\n"

之前的全部刷新出来。**
举个例子:
在这里插入图片描述
会发现先出来"\n"之前的,剩下的程序结束才出来:
在这里插入图片描述

2. 缓冲区满了进行刷新
3. 强制刷新。

ffush

把特定文件流进行刷新:
在这里插入图片描述
在Linux下一切皆文件,可以把显示器当文件看。
在C语言中程序在启动时默认会打开三个输入输出流:

stdin

对应的设备是键盘,

stdout

stderr

对应的是显示器。
在这里插入图片描述
在系统中不管是设备还是文件一律都是FILE。
一般打印输出用到的是stdout,显示到显示器上。

为什么会默认打开这输入输出流?
方便用户进行输入和输出。一般使用计算机的都有输入和输出的需求,所以一般就默认打开输入输出流,就不用在写代码打开上面键盘和显示器这些设备了。

在代码中使用一下

fflush

1#include<stdio.h>2#include<unistd.h>34 int main()5{6   printf("hello world,hello...");7   fflush(stdout);8   sleep(3);9return0;10}

在这里插入图片描述
编译发现缓冲区内容就直接冲刷出来了:
在这里插入图片描述
在这里插入图片描述
为什么会存在缓冲区?
缓冲区提高了用户效率。以前的printf是往硬件上写的,现在直接写到内存了。从内存拷贝内存数据的效率,肯定比从硬件拷贝到内存的效率高。
它刷新的次数越少,单次刷新的数据量越大,效率越高。
按行刷新是方便用户阅读。

4. 进度条

4.1 倒计时设置

假设将格子是光标的位置,一般在输入的时候就会是下面这样的:
在这里插入图片描述
但是如果想要实现光标在同一个位置,实现倒计时的感觉,就行下面这样:用8会覆盖这个9。
在这里插入图片描述
但是8会覆盖这个9后,光标会往后走,想要把在8的位置输出7,光标就得回到8的位置,7就把8覆盖,依此类推,就能实现一个动态的倒计时。
就是在同一个位置不停的覆盖,就能实现动态效果。
在这里插入图片描述
用代码来实现一下倒计时的感觉:
在这里插入图片描述
但这个代码输出并不是我们所想要的输出:
在这里插入图片描述


来修改一下代码,加上

"\r"

:
在这里插入图片描述
这里发现暂停一段时间,数据并没有显示出来:
在这里插入图片描述

"\r"

相当于我们写了一个数回到最开始,就清了一个数,所以最后什么也不显示。


那就直接加一个强制刷新缓冲区:

1#include<stdio.h>2#include<unistd.h>34 int main()5{6   int count=9;7   while(count>=0)8{9     printf("%d\r",count);10     fflush(stdout);11     count--;12     sleep(1);13}14return0;15}

来看看效果:
在这里插入图片描述


既然能够覆盖一个字符,那么肯定也能覆盖一个字符串。

1#include<stdio.h>2#include<unistd.h>34 int main()5{6   int count=9;7   while(count>=0)8{9     printf("倒计时:%d\r",count);10     fflush(stdout);11     count--;12     sleep(1);13}14   printf("\n");15return0;16}

来看看效果图:
在这里插入图片描述
在这里插入图片描述
如果从10开始:
在这里插入图片描述
就会出现这样的效果:
在这里插入图片描述
数字10,实际在显示器上显示的是字符,它转化成1字符和0字符。当在打印的9时候字符长度变短了,0就没有办法覆盖,就会一直在。
所以这里用%2d:
在这里插入图片描述
这时候就没有问题了:
在这里插入图片描述

4.2 进度条

这里用多文件来实现,Processbar.h用来声明,Processbar.c用来实现方法,Main.c用来调用Processbar.c里面的方法,再使用Makefile来实现自动化调用。
在这里插入图片描述

先写出基本的框架逻辑:
在这里插入图片描述

在这里插入图片描述

在编译的时候不用.h文件,因为在.c文件中已经包含.h是在当前目录下的,在编译时候会展开头文件的。
在Makefile里面写:

1 processbar:Main.c Processbar.c
  2   gcc -o$@ $^ 
  3 .PHONY:clean
  4 clean:
  5rm-f processbar

测试一下代码:
在这里插入图片描述

4.2.1 实现简单进度条

先画出进度条的示例:
进度条在增加的同时,当前的进度也在变化,光标也在不停的旋转。
在这里插入图片描述

这个进度条实现的时候,缓冲区的长度从0%到100%,但是还得考虑"\0",所以长度定义为101。
把缓冲区清空就用到

memset


在这里插入图片描述

想要在缓冲区里面写特殊符号,就直接用

define

:

#define Style '#'

用循环来实现动态进度条打印,直接打印相对应的字符串,和倒计时一样用

fflush(stdout);

来刷新缓冲区,随着时间的增加,进度条也在不断增加:
在这里插入图片描述
来看看效果:
在这里插入图片描述
发现这里打印时间太慢了。

使用

usleep

,它休眠的时间比

sleep

的小,所以这里就用

usleep

来进行休眠。
在这里插入图片描述
然后将字符串输出改为左对齐,加上进度条对应的比率:
在这里插入图片描述

来看看效果:
在这里插入图片描述

4.2.2 进度条完善

但是一般进度条不会单独出现,只有当我们下载一个文件同时出现。
这里就先模拟下载过程,就在在

Main.c

写一个

download

来实现。一般在下载一个文件的时候,会有下载文件的大小和下载到多少,和网络的带宽。
分别用变量定义一下文件大小,当前下载进度和带宽:

double filesize =1024*1024*1024*1.0;
double current =0.0; 
double bandwidth =1024*1024*1.0;

还可以加上一个开始下载的提示:

printf("download begin,current: %lf\n",current);

和下载完成的提示:


printf("\ndownload done,filesize: %lf\n",filesize);

在下载过程中把要下载的文件大小,和目前已经下载的大小传给进度条

ProcBar

,让进度条时时交互。
在这里插入图片描述

Processbar.h

中记得把在

Processbar.c

使用的打印进度条函数声明一下:

void ProcBar(double total,double current);

在这里插入图片描述

Processbar.c

中,就和上面的简单实现进度条一样,把文件的长度,和目前下载的长度传进去:

void ProcBar(double total,double current)

这里加了当前下载的进度百分比

double rate=(current*100.0)/total;

在循环的时候得将前下载的进度输出,循环的时候得把

double

rate的类型转为

int

int loop_count=(int)rate;

最后打印出当前下载的进度,还得冲刷缓冲区:

  printf("[%-100s][%.1lf%%][%c]\r",bar,rate,lable[cnt%len]);
  fflush(stdout);

来看看效果
在这里插入图片描述

在这里插入图片描述

Processbar.h

中定义一个函数指针类型:

typedef void(*callback_t)(double,double);

然后在

Main.c

里面将

download

改一下,可以根据文件的大小来下载:

void download(double filesize,callback_t cb)

在download函数里面直接执行:

cb(filesize,current);

方法。
为什么要这么写?
在之后如果用户写一个图形化界面的进度条,就能在下载的时候同时更新图形化界面。
在这里插入图片描述

也可以让进度条加上颜色,只需要在网上找一个关于用C语言输出有颜色相关的内容也就会有了。
这里是加了颜色效果:

 printf("\033[40;44m[%-100s][%.1lf%%][%c]\r\033[0m",bar,rate,lable[cnt%len]);

在这里插入图片描述

在这里插入图片描述

5. 附进度条代码

5.1 Processbar.h

1#pragma once23#include<stdio.h>45 typedef void(*callback_t)(double,double);6 void ProcBar(double total,double current);7 //extern void ForTest();

5.2 Processbar.c

1#include "Processbar.h"2#include <string.h>3#include <unistd.h>45#define Length 1016#define Style '#'78 const char *lable ="|/-\\";91011 void ProcBar(double total,double current)12{13   char bar[Length];14   memset(bar,'\0',sizeof(bar));15   int len=strlen(lable);1617   int cnt =0;18   double rate=(current*100.0)/total;19   int loop_count=(int)rate;20   while(cnt<=loop_count)21{22     bar[cnt++]=Style;2324}2526    //没有加颜色前的输出 printf("[%-100s][%.1lf%%][%c]\r",bar,rate,lable[cnt%len]);
        printf("\033[40;44m[%-100s][%.1lf%%][%c]\r\033[0m",bar,rate,lable[cnt%len]);27     fflush(stdout);28}

5.3 Main.c

1#include"Processbar.h"2#include <unistd.h>34 double bandwidth =1024*1024*1.0;5 void download(double filesize,callback_t cb)6{7   double current =0.0;8910   printf("download begin,current: %lf\n",current);11   while(current<=filesize)12{13     cb(filesize,current);14     usleep(100000);15current+=bandwidth;1617}18   printf("\ndownload done,filesize: %lf\n",filesize);19}202122 int main()23{24   download(101*1024*1024,ProcBar);25  // ProcBar(100.0,56.9);2627 // ProcBar(100.0,1.0);28  // ProcBar(100.0,99.9);2930  // ProcBar(100.0,100);31   //ForTest();32return0;33}
~

5.4 Makefile

1 processbar:Main.c Processbar.c
  2   gcc -o$@ $^ 
  3 .PHONY:clean
  4 clean:
  5rm-f processbar

有问题请指出,大家一起进步吧!!!

标签: linux 小程序 运维

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

“【Linux】实现进度条小程序”的评论:

还没有评论