行业知识
【Linux旅行记】进度条小程序
���近,我发现了一个超级强大的人工智能学习网站。它以通俗易懂的方式呈现复杂的概念,而且内容风趣幽默。我觉得它对大家可能会有所帮助,所以我在此分享。点击这里跳转到网站。
文章目录
- 一、预备知识
- 1.1回车换行
- 1.2缓冲区
- 二、倒计时
- 三、进度条
- 3.1普通版本源代码
- 3.2高级版本源代码
- 小结
博客主页:小智_x0___0x_
欢迎关注:点赞收藏✍️留言
系列专栏:Linux入门到精通
代码仓库:小智的代码仓库
一、预备知识
1.1回车换行
我们一般意义上的回车换行是两个概念,一般我们在C语言上的\n的作用是回车+换行,他把两个操作都做了,但是\转义字符也有别的的作用,我们一般回车是回车,换行是换行,两个是不同的概念。回车是指讲光标移动到当前行的最左侧开始位置,换行指的是光标水平方向保持不变,向下平移一行,C语言中有一个\r就是实现回车功能。
我们平时用的键盘上面有一个Enter的按键,这个按键就是实现了我们的回车+换行的作用。
1.2缓冲区
我们先来看一段代码:
#include "processBar.h"#include int main(){ printf("hello world\n"); sleep(2); return 0; }这个程序是输出一个hello world 然后再让程序休眠2秒,这里的sleep函数是系统函数功能是让程序休眠指定时间,我们可以通过man 3 sleep手册来查看sleep函数的使用方法。
我们来运行这个代码来看看效果:
这里可以看到的现象是,程序先完成了打印hello world再休眠两秒钟。
我们再来改改代码:
#include "processBar.h"#include int main(){ printf("hello world"); sleep(2); return 0;}这次我们把\n去掉,此时程序会是怎么样的呢,先打印还是先休眠,我们一起来验证一下:
可以看到我们把\n去掉之后程序是先休眠了两秒,接着再在显示器上打印出hello world,这次没有换行符,所以bash命令行就会紧接在hello world的后面。
那么事实真的是这样的嘛?
我们可以来想一想,一个C语言程序是严格按照代码顺序从上往下依次执行的,不管怎样都是这样,肯定是先执行打印printf在进行sleep休眠2秒,但是此时又有一个疑问了,为什么我们printf的内容没有显示出来呢?在我sleep期间hello world在哪里?
一定被保存起来了,那么要保存就一定需要内存空间,这里其实就是保存在来我们的缓冲区里面,这里的缓冲区是由C语言维护的一段内存
所以当程序执行结束的时候才会将缓冲区中的内容刷新出来。
那我们要强制刷新呢?
这里我们就要知道一个C语言程序运行会默认帮我们打开这三个流:
- stdin - - - -标准输入流(键盘)
- stdout - - - - 标准输出流(显示器)
- stderr - - - -标准错误流(显示器)
在我们平时使用文件操作的时候打开一个文件也是用的FILE *类型来打开文件。
那么我们要强制刷新就要用到这个函数fflush
这里刚好就是接收FILE* 类型。
具体操作:
#include "processBar.h"#include int main(){ printf("hello world"); fflush(stdout); sleep(2); return 0;}我们其实打印出的数据是往stdout中打印的,所以我们在printf后面紧接着一个fflush来强制刷新。
我们来运行看看现象:
可以看到这次我们是先显示出了hello warld再休眠两秒,bash的命令行才刷新出来。
总结:
- \n可以刷新缓冲区
- fflush可以强制刷新缓冲区
- 程序结束可以刷新缓冲区
二、倒计时
有了上面的基础我们可以简单的来实现一个倒计时:
#include "processBar.h"#include int main(){ int cnt=10;//定义倒计时时间 while(cnt>=0) { printf("%-2d\r",cnt);//%-2d 表示以两个字符位输出并以左对齐方式输出 `\r`表示只回车不换行 fflush(stdout);//强制刷新缓冲区 cnt--; sleep(1);//程序休眠1s } printf("\n"); return 0;}我们再来看看效果:
在这段代码中,%-2d\r的作用是实现倒计时效果。%-2d表示以两个字符位输出并以左对齐方式输出,%d是输出整数的占位符。\r表示回车到行首,即光标移到行首,而不换行。
因此,每次循环时,数字会被输出并覆盖上一次输出的数字,从而实现倒计时的效果。由于使用了\r回车到行首,所以数字输出在同一行上,不会换行。
另外,fflush(stdout)强制刷新缓冲区是为了确保每次输出都能够立即显示在屏幕上,而不是留在缓冲区中等待下一次输出。sleep(1)函数是让程序休眠1秒钟,以便实现倒计时效果。
三、进度条
设计思路:
- 确定进度条的显示方式,例如使用字符 ‘#’ 表示进度条的进度。
- 确定进度条的长度,例如设定进度条长度为100个字符。
- 计算进度条的进度,例如已完成任务的百分比为 50%,则进度条应该显示50个 ‘#’ 字符。
- 每次更新进度条时,先将光标移动到行首,然后输出当前进度条的状态,再将光标移回到行首,以便下一次更新。
- 可以使用定时器或者其他方式控制进度条的更新速度,例如每隔1秒更新一次进度条。
3.1普通版本源代码
processBar.h
#pragma once #include#define NUM 102 // 进度条长度#define TOP 100 // 进度条最大值#define BODY '=' // 进度条已完成部分的字符#define RIGHT '>' // 进度条右边界的字符// 进度条函数的声明extern void processbar(int speed);
processBar.c
#include "processBar.h"#include #include // 进度条的四种状态,即 |、/、-、\const char *lable="|/-\";void processbar(int speed){ char bar[NUM]; // 存储进度条的字符数组 memset(bar,'',sizeof(bar)); // 初始化进度条数组 int len = strlen(lable); // 计算进度条状态的长度 int cnt = 0; // 进度条的当前值 while(cnt printf("[%-100s][%d%%][%c]\r",bar,cnt,lable[cnt%len]); // 输出进度条信息 fflush(stdout); // 刷新缓冲区,使得程序能够立即输出 bar[cnt++]= BODY; // 将 BODY 字符加入到进度条数组中,并将当前值加1 if(cnt processbar(100000); return 0;}0};void processbar(int rate){ if(rate