前言
进度条在我们日常生活中非常常见,比如下载文件、加载游戏时会有一个进度条方便我们确认当前的进度。在Linux中我们使用yum下载软件时也会出现进度条显示文件当前的下载进度,本文将会实现在Linux命令行中的进度条显示。
进度条
呈现效果
在开始实现具体代码之前,先来看看最终呈现的效果:
前置知识 - 回车换行
在以往写代码中(C语言的printf),我们经常使用换行符\n
以使本行打印完毕后使光标换到下一行的开始(最左边)。
示例
例子1:
换行符\n
直接把缓冲区的hello world刷新到显示器上,之后程序休眠2秒结束。并且\n
使光标换到下一行并回到最开始的位置,所以命令提示符也会出现在下一行的开始位置。
例子2:
结尾没有\n
,缓冲区的hello world在第5行代码执行完后显示器不显示,之后程序休眠2秒,程序结束时把缓冲区的内容hello world显示到显示器上,并且光标在其之后,而不是在下一行开始,现象就是命令提示符直接在hello world之后显示。
第6行的fflush函数把缓冲区的内容(hello world)刷新到了显示器上,光标位置仍然在hello world的下一个位置
换行符\n
**换行符,顾名思义就是把光标换到下一行,同时刷新行缓冲区,把行缓冲区的内容打印到显示器上。**这本来并不会把光标回到这一行的开始(这是回车\r
)的功能,但是,编译器对换行符\n
做了特殊处理,当只出现\n
时会同时完成回车与换行的功能,使光标换到下一行并回到最开始的位置。
回车符\r
**回车符,把光标回退到本行的最开始位置。**回车符\r
不会刷新缓冲区,所以缓冲区的内容不会被刷新到显示器上,导致的结果就是待打印的内容仍在缓冲区中,显示器上没有内容(不了解这一特性时,会怀疑程序是不是出问题了,其实并不是)。
要想正常显示缓冲区的内容,只需再加一句刷新缓冲区的代码(fflush)即可。
思路讲解
实现进度条增长,现象是进度条越来越长直到进度条达到最长时停止。
用字符数组来实现,进度为0%时进度条为0,进度为1%时进度条为1个字符…进度为100%时进度条为100个字符。
#define NUM 101// 进度条长度
char bar[NUM];
memset(bar, '\0', sizeof(bar));//初始化字符数组bar所有元素为'\0'
循环输出字符数组,每次输出字符数组之后,光标都要回到本行的最开始\r
,然后字符数组内容+1;
单独使用\r
待打印的内容会储存在缓冲区中,不会显示在屏幕上,所以需要使用fflush
函数刷新缓冲区。
printf("[%-100s][%3d%%]\r", bar, cnt);
fflush(stdout);
旋转光标的实现:在进度条加载中,其后经常会有一个持续旋转的圆圈,我采用"|/-\\"
四个字符依次循环出现模拟旋转的光标。
char spin[5] = "|/-\\";
printf("%c", spin[cnt % 4];);
进度条总进度为[0%, 100%],本例使用长度为101字符数组表示进度条主体,为了不使循环直接结束,每次循环都使程序休眠usleep
(10^(-6)s)一定时间,也方面我们控制进度条执行的时间。
#define FIXEDTIME 5 //单位s
#define SPEED 1
usleep(FIXEDTIME / SPEED * 10000);
printf的颜色控制:
格式为:\033[属性1;属性2…;m
以**\033开头,[与m中间是各种属性(某个数字表示),属性之间以;**分隔。
- 格式控制:
0 重置所有属性
1 高亮/加粗
5 闪烁
- 字体颜色:
30 黑色
31 红色
32 绿色
33 黄色
34 蓝色
35 品红
36 青色
37 白色
- 背景颜色:
40 黑色
41 红色
42 绿色
43 黄色
44 蓝色
45 品红
46 青色
47 白色
代码实现
头文件progressBar.h
#pragma once
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#define NUM 101 //进度条长度
#define FIXEDTIME 5 // 5s
#define SPEED 2 //固定时间/SPEED
extern void progressBar();
源文件main.c
#include "progress.h"
int main(){
progressBar();
return 0;
}
源文件progressBar.c
#include "progress.h"
void progressBar(){
char bar[NUM];
char spin[5] = "|/-\\";
const char* style = "*-+=#";
memset(bar, '\0', sizeof(bar));
int cnt = 0;
while(cnt <= 100){
printf("\033[47;31m[%-100s][%3d%%][%c]\r\033[0m", bar, cnt, spin[cnt % 4]);
fflush(stdout);
usleep(FIXEDTIME / SPEED * 10000);// 睡眠
//sleep(1);
bar[cnt++] = style[N];
}
printf("\n");
}
结语
T h e E n d TheEnd TheEnd