进度条制作--Linux知识的小应用
目录
一:回车与换行
二:缓冲区
三:显示器类型概念
四:进度条制作
4.1倒计时程序
4.2进度条制作
一:回车与换行
回车:回到这一行的起点 \r
换行:换到下一行与该行相同的位置 \b
先回车再换行,可以达到在新的一行从头开始
二:缓冲区
\n:可以刷新缓冲区,把缓冲区的内容输出
根据上面的代码和运行结果可以看出,如果代码最后有\n,结果是先打印结果,然后睡眠2秒
如果代码最后没有\n,结果是先睡眠2秒,然后在打印结果,且最后没有换行
是\n,改变了代码执行顺序吗?
不,不管最后有没有\n,代码执行程序都是从上往下,先执行printf,再执行sleep,但是不带\n的现象感觉是先执行sleep,然后执行printf呢?如果都是先执行printf,那么不带\n的情况下,执行完的printf,原本该在显示器打印出来的字符串在哪里呢?----缓冲区
一种刷新是程序执行完,退出的时候,将缓冲区的内容一次性刷新到显示器中,这就是不带\n的时候,为什么先看到sleep的现象,再看到打印的字符串
另外一种就是\n,\n表示一种强制刷新,是行刷新,遇到\n会将缓冲区一行的内容刷新到显示器中
还有一种刷新方式就是fflush刷新
使用fflush就可以达成刷新缓冲区,但是不换行
三:显示器类型概念
我们在定义的时候,a是int类型的,预料中打印应该是整数1234,结果也和预期是一样的
但是打印的是整数1234,还是1 2 3 4这四个字符,组合起来让我们以为是整数呢?
结论是:显示器没有类型概念,它在打印的时候是一个一个字符打印的
那为什么它的显示结果还和我们预想的一样呢?
四:进度条制作
4.1倒计时程序
根据上面的知识,我们可以实现一个小的倒计时程序,即在同一个行实现数字变换,从9->0
int main()
{int cont = 10;while(cont--){printf("%d\r",cont);fflush(stdout);sleep(1);}printf("\n");return 0;
}
如果使用上述代码执行,10->0呢?
此时会有一个新的问题,10在显示器来说是两个字符,但是9到0只是一个字符,此时就会出现,9到0,只会更换一个字符,另一个字符保持不变,如果要改变这种情况,就要把0~9变成两个字符
4.2进度条制作
在知道倒计时程序的使用之后,可以进一步制作进度条,首先我们要明确进度条都需要哪些要素?
1.有一个进度框,框里面是进度条的移动,一般是一次性大小就固定不动
2.进度条随着进度的执行,在进度框里面向后移动
3.会显示当前进度的数字
4.有的时候进度数字后面还有一个交替变换的加载符号
根据上面的要素,以及前面的知识,可以写一个进度条代码:
process.h
#pragma once
#include <stdio.h>
#include <unistd.h>
#include <string.h>void Process();
process.c
#include "process.h"#define NUM 101
#define STYLE '='//效果[====> ] [ ] [ ],最后>会消失
void Process()
{const char* lable = "|/-\\";int len = strlen(lable);char bar[NUM];memset(bar,'\0',sizeof(bar));int cnt = 0;while(cnt <= 100){printf("[%-100s][%d%%][%c]\r",bar,cnt,lable[cnt%len]);//进度条主体fflush(stdout);//刷新缓冲区,显示到显示器中bar[cnt] = STYLE;cnt++;//处理最后一个字符if(cnt == NUM){bar[cnt-1] = '\0';printf("[%-100s][%d%%][%c]\r",bar,cnt-1,lable[(cnt-1)%len]);//进度条主体break;}bar[cnt] = '>';usleep(50000);//unsleep单位是微秒,sleep单位是秒}
}
main.c
#include<stdio.h>
#include "process.h"int main()
{Process();return 0;
}
Makefile:
process : process.c main.cgcc -std=c99 -o $@ $^.PHONY : clean
clean:rm -rf process
运行结果:
4.3进度条的场景应用
进度条一般用在下载量,动态刷新...
下面模拟一下进度条在下载量的实际应用:
process.h
#pragma once
#include <stdio.h>
#include <unistd.h>
#include <string.h>void FlushProcess();
process.c
#include "process.h"#define NUM 101
#define SPACE ' '
#define STYLE '='
#define POINT '.'
const int pnum = 3;void FlushProcess(double total, double current)
{//1.更新当前的百分比double rate = (current / total)*100;//2.更新当前的进度条char bar[NUM];//每1%更新一个进度条memset(bar,'\0',sizeof(bar));for(int i = 0; i < (int)rate;i++){bar[i] = STYLE;}//3.更新旋转光标,...的数量//为什么要加上旋转光标?//如果进度条缓慢,每次进入函数,取整之后进度条没有变化,此时可以通过旋转光标有无变化来判断程序是否在正常运行static int num = 0;num++;num %= pnum;char points[pnum+1];for(int i = 0; i < pnum;i++){if(i < num)points[i] = POINT;elsepoints[i] = SPACE;}//4.打印进度条printf("[%-100s][%.1lf%%]%s\r",bar,rate,points);fflush(stdout);
}
main.c
#include<stdio.h>
#include "process.h"
#include<time.h>
#include <stdlib.h>typedef void(*flush_t) (double total,double current); //函数指针const int base = 20;//单词下载量的基础值
double total = 2048.0;//需要下载的量
double once = 0.1;//速度void download(flush_t f)
{double current = 0.0;while(current < total){//模拟下载行为int r = rand()%base+1;double speed = r * once;current += speed;if(current > total) current = total;usleep(10000);//更新本次下载量f(total,current);}printf("\n");
}int main()
{srand(time(NULL));download(FlushProcess);download(FlushProcess);download(FlushProcess);download(FlushProcess);return 0;
}
Makefile
process : process.c main.cgcc -std=c99 -o $@ $^.PHONY : clean
clean:rm -rf process
运行结果: