我们再将
Linux
常用工具与命令都学会了之后,设计进度条这个小程序可以比较好的帮助我们进行一定程度练习与巩固
视频演示
目录
预备知识:
在开始之前我们需要有两个预备知识,可以更好的辅助我们进行设计程序。
回车换行:
我们经常说的回车换行其实是两个概念
回车 :
代表从你现在的位置到你本行起始的位置,转义字符为'\r'
换行 :
仅仅只是从本行的当前位置到移动到下一行。一般没有此操作的转义字符,大多数情况下都是'\n'
既包括了换行与回车;
缓冲区:
我们先运行如下代码:
c
#include <stdio.h>
int main()
{
printf("hello Makefile!\n");
sleep(3);
return 0;
}
发现终端会停止3s在出现hello Makefile!
字符串,
这也就说明了缓冲区的存在在,
但是现阶段我们是很难对缓冲区有深刻理解的,
只需要知道他的存在会造成什么影响即可
缓冲区是内存中的一段空间,当程序结束或者遇到
'\n'
时会刷新缓冲区,也可以选择使用
fflush(stdout)
进行主动刷新缓冲区
证明方法:
c
#include <stdio.h>
int main()
{
printf("hello Makefile!");
fflush(stdout);
sleep(3);
return 0;
}
我们在sleep
前fflush
进行刷新即可发现结论成立
进度条:
进度条是个比较简单的小程序,有了大概得思想,实现起来细心一点是没什么大问题的。
准备工作:
此准备工作非预备工作,
这部分主要是构建makefile方便我们进行自动构建
首先还是老样子,touch上3个文件,进行声明与定义分离,还有个main文件
在makefile中进行配置。
主题思路:
每次打印时实际上都对上一次打印的数据进行覆盖,
并且每一次打印的数据都是根据当前进度进而改变进度条增加的长度。
我们打算搞一个如上图的进度条
代码实现:
有了预备知识作为铺垫,思想也有了,代码还是信手拈来的
注意 :
此时我们并不是仿真,而是先设计一个进度条框架,随后再进行仿真设计
c
#define length 101
#define style '-'
const char* table = "-\\|/";
void ProgBar()
{
char str[length] = {0};
int count = 0;
while(count <= 100)
{
printf("[%-100s][%d%%][%c]\r", str, count, table[count%4]);
fflush(stdout);
str[count++] = style;
usleep(50000);
}
printf("\n");
}
模拟实际场景:
也不是完全的模拟,只是我们自己设置了带宽与总大小,得到一个相对应的比例,没有将带宽设置随机
可以在Main
文件中造一个模拟下载的环境,同时使用回调函数的方式进行传参
c
double bandwidth = 1024*1024*1.0;
void download(double filesize, back_t func)
{
printf("download begin filesize:%lf\n", filesize);
double current = 0;
while(current <= filesize)
{
func(filesize, current);
current += bandwidth;
usleep(50000);
}
printf("\ndownload down filesize:%lf", filesize);
printf("\n");
}
int main()
{
//博主用来测试的函数
download(1024*1024*10, ProgBar);
download(1024*1024*90, ProgBar);
download(1024*1024*60, ProgBar);
download(1024*1024*40, ProgBar);
return 0;
}
将定义文件中的函数进行一些微调
c
#define length 101
#define style '-'
const char* table = "-\\|/";
void ProgBar(double total, double current)
{
char str[length] = {0};
int count = 0;
int len = strlen(table);
double rate = (current / total)*100;
while(count <= (int)rate)
{
str[count++] = style;
}
printf("[%-100s][%.2lf%%][%c]\r", str, rate, table[count%len]);
fflush(stdout);
}
声明文件中:
c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include"color.h"
void ProgBar(double total, double current);
//回调函数的声明
typedef void (*back_t)(double, double);
关于色块:
关于色块博客链接,这里介绍了如何输出的用法,博主是直接粘贴过来缝缝补补直接用上了
代码实现基本逻辑是一致的,无非是变成了多次输出才形成一个完整的进度条
c
//version1 color
void ProgBar()
{
char flag[] = {'-', '\\', '|', '/'};
int len = strlen(flag);
int i = 0;
int j = 0;
int cnt = 0;
while(cnt <= 100)
{
i = cnt;
j = 100 - cnt;
//这段i的while循环就是生成色块的关键,其中的reverse是宏定义
while(i--)
{
printf(REVERSE " " NONE);
}
while(j--)
{
printf(" ");
}
printf("[%d%%][%c]\r", cnt, flag[cnt%len]);
cnt++;
fflush(stdout);
usleep(50000);
}
printf("\n");
}
这是宏定义的代码(上边放的博客链接有具体的):
c
#define NONE "\e[0m" //清除颜色,即之后的打印为正常输出,之前的不受影响
#define BLACK "\e[0;30m" //深黑
#define L_BLACK "\e[1;30m" //亮黑,偏灰褐
#define RED "\e[0;31m" //深红,暗红
#define L_RED "\e[1;31m" //鲜红
#define GREEN "\e[0;32m" //深绿,暗绿
#define L_GREEN "\e[1;32m" //鲜绿
#define BROWN "\e[0;33m" //深黄,暗黄
#define YELLOW "\e[1;33m" //鲜黄
#define BLUE "\e[0;34m" //深蓝,暗蓝
#define L_BLUE "\e[1;34m" //亮蓝,偏白灰
#define PURPLE "\e[0;35m" //深粉,暗粉,偏暗紫
#define L_PURPLE "\e[1;35m" //亮粉,偏白灰
#define CYAN "\e[0;36m" //暗青色
#define L_CYAN "\e[1;36m" //鲜亮青色
#define GRAY "\e[0;37m" //灰色
#define WHITE "\e[1;37m" //白色,字体粗一点,比正常大,比bold小
#define BOLD "\e[1m" //白色,粗体
#define UNDERLINE "\e[4m" //下划线,白色,正常大小
#define BLINK "\e[5m" //闪烁,白色,正常大小
#define REVERSE "\e[7m" //反转,即字体背景为白色,字体为黑色
#define HIDE "\e[8m" //隐藏
#define CLRLINE "\r\e[K" //清除行
完整代码:
ProgressBar.h:
c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include"color.h"
//void ProgBar();
void ProgBar(double total, double current);
typedef void (*back_t)(double, double);
ProgressBar.c(有注释说明对应哪个版本):
version 1:无仿真
version 2:仿真
version 1 color:无仿真
version 2 color:仿真
c
#include"ProgressBar.h"
#define length 101
#define style '-'
const char* table = "-\\|/";
//version 1 no color
void ProgBar()
{
char str[length] = {0};
int count = 0;
while(count <= 100)
{
printf("[%-100s][%d%%][%c]\r", str, count, table[count%4]);
fflush(stdout);
str[count++] = style;
usleep(50000);
}
printf("\n");
}
//version 2 no color
//void ProgBar(double total, double current)
//{
// char str[length] = {0};
// int count = 0;
// int len = strlen(table);
// double rate = (current / total)*100;
//
// while(count <= (int)rate)
// {
// str[count++] = style;
// }
// printf("[%-100s][%.2lf%%][%c]\r", str, rate, table[count%len]);
// fflush(stdout);
//}
//version1 color
//void ProgBar()
//{
// char flag[] = {'-', '\\', '|', '/'};
// int len = strlen(flag);
//
// int i = 0;
// int j = 0;
// int cnt = 0;
// while(cnt <= 100)
// {
// i = cnt;
// j = 100 - cnt;
// while(i--)
// {
// printf(REVERSE " " NONE);
// }
// while(j--)
// {
// printf(" ");
// }
// printf("[%d%%][%c]\r", cnt, flag[cnt%len]);
// cnt++;
// fflush(stdout);
// usleep(50000);
// }
// printf("\n");
//}
//version2 color
//void ProgBar(double total, double current)
//{
// double rate = current*100/total;
//
// int i = 0;
// int j = 0;
// int cnt = (int)rate;
//
// i = cnt;
// j = 100 - cnt;
// while(i--)
// {
// printf(REVERSE " " NONE);
// }
// while(j--)
// {
// printf(" ");
// }
// printf("[%.2lf%%][%c]\r", rate, table[cnt%4]);
// fflush(stdout);
//}
Main.c:
c
#include"ProgressBar.h"
double bandwidth = 1024*1024*1.0;
void download(double filesize, back_t func)
{
printf("download begin filesize:%lf\n", filesize);
double current = 0;
while(current <= filesize)
{
func(filesize, current);
current += bandwidth;
usleep(50000);
}
printf("\ndownload down filesize:%lf", filesize);
printf("\n");
}
int main()
{
download(1024*1024*10, ProgBar);
download(1024*1024*90, ProgBar);
download(1024*1024*60, ProgBar);
download(1024*1024*40, ProgBar);
//ProgBar();
//ProgBar(100, 59.9);
return 0;
}
color.h
c
#define NONE "\e[0m" //清除颜色,即之后的打印为正常输出,之前的不受影响
#define BLACK "\e[0;30m" //深黑
#define L_BLACK "\e[1;30m" //亮黑,偏灰褐
#define RED "\e[0;31m" //深红,暗红
#define L_RED "\e[1;31m" //鲜红
#define GREEN "\e[0;32m" //深绿,暗绿
#define L_GREEN "\e[1;32m" //鲜绿
#define BROWN "\e[0;33m" //深黄,暗黄
#define YELLOW "\e[1;33m" //鲜黄
#define BLUE "\e[0;34m" //深蓝,暗蓝
#define L_BLUE "\e[1;34m" //亮蓝,偏白灰
#define PURPLE "\e[0;35m" //深粉,暗粉,偏暗紫
#define L_PURPLE "\e[1;35m" //亮粉,偏白灰
#define CYAN "\e[0;36m" //暗青色
#define L_CYAN "\e[1;36m" //鲜亮青色
#define GRAY "\e[0;37m" //灰色
#define WHITE "\e[1;37m" //白色,字体粗一点,比正常大,比bold小
#define BOLD "\e[1m" //白色,粗体
#define UNDERLINE "\e[4m" //下划线,白色,正常大小
#define BLINK "\e[5m" //闪烁,白色,正常大小
#define REVERSE "\e[7m" //反转,即字体背景为白色,字体为黑色
#define HIDE "\e[8m" //隐藏
#define CLRLINE "\r\e[K" //清除行