🎉博主首页:
有趣的中国人
🎉专栏首页:
Linux
🎉其它专栏:
C++初阶 |
C++进阶 |
初阶数据结构
小伙伴们大家好,本片文章将会讲解
Linux
中
进度条的实现
的相关内容。
如果看到最后您觉得这篇文章写得不错,有所收获,麻烦点赞👍、收藏🌟、留下评论📝。您的支持是我最大的动力,让我们一起努力,共同成长!
文章目录
1. 关于回车 & 换行
回车和换行是文本显示和处理的相关术语,我们常常认为这两个是同一概念,实则不然。
👨💻回车换行的概念
回车(Carriage Return):在打字机时代,回车指的是将打字机的打印头(称为"carrier")移回到行首的操作。在计算机时代,回车通常表示将光标移动到当前行的开头,而不会换到下一行。在
ASCII
字符集中,回车通常用"
\r
"表示。
换行(Line Feed)::换行是指将光标移动到下一行的操作,使得文本在纵向上向下移动一个行高。在
ASCII
字符集中,换行通常用"
\n
"表示。
在Unix和类Unix系统(如
Linux
和
macOS
)中:通常使用换行字符(“
\n
”)来表示换行。
在Windows系统中:,通常使用回车和换行的组合来表示换行,即"
\r\n
"。
2. 简述缓冲区
缓冲区(
Buffer
)是计算机内存中的一块特定区域,用于临时存储数据。它在许多计算机系统和应用程序中发挥着重要作用,通常用于临时存储输入数据、输出数据或在内存和其他设备之间进行数据传输。
输入缓冲区:用于暂时存储从输入设备(如键盘、鼠标、网络接口等)接收到的数据,直到程序能够处理它们。输入缓冲区使得程序可以按需处理输入,而不必担心输入数据的速度与程序处理速度不匹配的问题。
输出缓冲区:用于暂时存储将要发送到输出设备(如显示器、打印机、网络接口等)的数据,直到设备准备好接收它们。输出缓冲区可以提高数据传输的效率,因为程序不必等待设备就绪就可以继续执行。
👨💻缓冲区何时被清理
拿C语言举个例子:
在C语言中,标准库函数
printf()
用于将格式化的数据打印到标准输出流(通常是终端)。但是,
printf()
函数并不会立即将数据显示到终端上。相反,它会将数据写入到输出缓冲区中。输出缓冲区是一个临时存储区域,用于存放
printf()
函数打印的数据,直到满足一定条件时才将其刷新(即将数据发送到终端并显示出来)。
这些条件包括:
遇到换行符
\n
:当
printf()
函数遇到换行符时,输出缓冲区会被自动刷新,将缓冲区中的数据输出到终端并显示出来。
缓冲区满:当输出缓冲区满了,它也会被自动刷新。
3.调用fflush()函数:显式调用
fflush(stdout)
函数可以强制刷新输出缓冲区,将其中的数据输出到终端。
- 程序结束:当程序正常终止时,所有的缓冲区都会被刷新。
3. 倒计时程序的编写
有了以上的知识储备,咱们就可以尝试编写一下简单的倒计时程序了,思路如下:
- 首先新建一个
time.c
文件,然后再用我们之前讲的makefile
工具来实现time.c
文件的自动构建:
- 编写
time.c
这个文件,实现思路:
- 假设我们倒数
10s
,到0s
时结束,因此需要一个循环;- 循环中,我们要实现每次出来一个数,都要对之前的数进行覆盖,所以要用到回车"
\r
";- 由于
printf()
函数会会将输出的结果先输出到缓冲区,回车不会冲刷缓冲区,因此每次要用fflush(stdout)
强制冲刷缓冲区;- 每次循环
秒数减1
,并让程序休眠1s
。
🌝详细代码如下:
#include<stdio.h>#include<unistd.h>intmain(){int cnt =10;while(cnt >=0){// 打印的时候每次覆盖上一次出现的数字printf("倒计时:%2d\r",cnt);// 强制冲刷缓冲区fflush(stdout);--cnt;sleep(1);}printf("\n");return0;}
- 用
make
命令进行编译:(⏳这边就可以动态运行了哈,感兴趣的可以自己试一下⌛)
- 这里有个小拓展,如果我们要覆盖上次的数字是4位,这次是三次(比如1000到999),可以用
%4d
这个输出形式来解决,也可以用下面这种方法:
#include<stdio.h>#include<unistd.h>intmain(){int cnt =1000;int tmp = cnt;int num =0;while(tmp){++num;
tmp /=10;}while(cnt >=0){// 主要就是这里的变化,用最大数字的位数来做占位符printf("倒计时:%*d\r",num, cnt);fflush(stdout);--cnt;sleep(1);}printf("\n");return0;}
4. 简易进度条的实现
好啦,有了以上的知识作为基础,咱们就可以进入正题啦!😎编写简易的进度条。😎
👨💻效果图展示
总共有三个部分:
我们要实现的进度条用
#
来进行加载;
后面要有数据来表示现在加载的进度是多少(百分数);
最后用一个动态旋转的类
⚪
来表示程序还在继续加载。
👨💻实现思路
- 动态加载的过程
动态加和之前的倒计时差不多,每次都要覆盖上次出现的
#
,具体思路如下:
定义一个字符类型数组
char *str
,用
memset()
函数进行初始化(‘
\0
’);
循环
100
次,每次循环都在数组中加一个
#
,并打印
str
('
\r
’进行覆盖);
强制冲刷缓冲区;
- 进度加载
我们可以用每次循环的次数来当作是当前加载的进度,当然还要进行覆盖,具体思路如下:
每次循环都以当前的循环次数作为加载进度;
每次覆盖上一次的进度;
强制冲刷缓冲区。
程序休眠(可以用
usleep()
函数,单位是微秒)
- 动态旋转
定义一个数组,并初始化为
-\\/-
,覆盖的方法和之前类似,就不详细说了。
👨💻具体代码实现
#include"process_bar.h"#include<memory.h>#include<unistd.h>#definestyle'#'#defineround"-\\/-"voidtest(){int i =0;char str[100];memset(str,'\0',sizeof(str));while(i <=100){
str[i]= style;printf("[%-100s][%d%%][%c]\r",str,i,round[i %4]);fflush(stdout);++i;usleep(10000);}printf("\n");}
👨💻第二版本
我们正常用进度条肯定不是单独使用的,会结合其他的场景,例如下载界面,登陆界面。
对于要下载的文件,肯定有文件大小,下载的时候网络也有它的带宽,所以在下载的时候,每次下载的大小都是一个带宽,我们可以先写一个下载的函数:
download函数:
void download(){
double bandwidth =1024*1024*1.0;
double filesize =1024*1024*10.0;
double cur =0.0;
while (cur <= filesize){// 调用进度条函数test(filesize, cur);// 每次增加带宽
cur += bandwidth;usleep(20000);}printf("\n");printf("this file has been downloaded\n");}
进度条函数:
void test(double total, double current){
char str[101];memset(str,'\0',sizeof(str));int i =0;// 这次的比率
double rate =(current *100)/ total;// 循环次数int loop_count =(int)rate;
while (i <= loop_count){
str[i++]= style;}printf("[%-100s][%.1lf%%][%c]\r",str,rate,round[loop_count %4]);fflush(stdout);}
回调函数版本(完整):
// 头文件 process_bar.h#include<stdio.h>typedefvoid(*callback_t)(double,double);// 函数指针(回调函数)voidtest(double total,double current);// 函数实现文件 process_bar.c#include"process_bar.h"#include<memory.h>#include<unistd.h>#definestyle'#'#defineround"-\\/-"voidtest(double total,double current){char str[101];memset(str,'\0',sizeof(str));int i =0;double rate =(current *100)/ total;int loop_count =(int)rate;while(i <= loop_count){
str[i++]= style;}printf("[%-100s][%.1lf%%][%c]\r",str,rate,round[loop_count %4]);fflush(stdout);}// main.c 主函数和 download 函数#include"process_bar.h"#include<unistd.h>double bandwidth =1024*1024*1.0;voiddownload(double filesize,callback_t cb){double cur =0.0;while(cur <= filesize){cb(filesize, cur);
cur += bandwidth;usleep(20000);}printf("\n");printf("this file has been downloaded\n");}intmain(){download(1024*1024*100.0,test);download(1024*1024*20.0,test);return0;}
版权归原作者 有趣的中国人 所有, 如有侵权,请联系我们删除。