Linux小程序 —— 进度条
前言:经过这么多天的学习,想必大家学到了许多Linux知识,本日我们来用Linux来实现我们的第一个小程序 — — 进度条https://img-blog.csdnimg.cn/direct/110f311c3cd24712b35eb0da6ae1c8a9.webp#pic_center
本篇告急内容将会实现三个版本的进度条:
[*]简单原理版本
[*]实际工程实践版本
[*]拓展版本
https://img-blog.csdnimg.cn/direct/b92ef4818232446099f712ab42607a13.gif#pic_center
在实现进度条之前,我们先了解一些之前没提到过的知识,以便我们明白
1. 缓冲区的概念
我们先来分析下面几段代码感受一下行缓冲区的存在:
在Linux当中以下代码的运行效果是什么样的?
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("你能看见我嘛\n");
sleep(2);
return 0;
}
这段代码运行效果显而易见:printf函数直接打印内容,然后休眠2秒。
对于大家大概没有什么难度。那如果我们修改一下代码。
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("你能看见我嘛");
sleep(2);
return 0;
}
缓冲区的概念
通过视频我们发现,我仅仅是将\n删除了,但是却带来了完全不一样的运行效果:先休眠2秒,然后才是printf函数打印内容
那么为什么会出现这种情况呢? C语言实行代码的逻辑不应该是从上至下实行吗?
[*]按照 C语言实行代码的逻辑printf确实已经运行了,只不过内容没有被表现出来!
[*]内容地点的地区则是在输出缓冲区中!
C/C++语言,会针对尺度输出,给我们提供默认的缓冲区
fflush函数可以刷新缓冲区,如果我们想立马显现可以用函数刷新fflush(),而\n是一种刷新的计谋——行刷新,所以\n也能立马显现!
2. \r&&\n
概念:
[*]\r: 回车,使光标回到本行首格
[*]\n: 换行,使光标移到下一行
光说大概大家不太明白,我们来实操看看:
#include <stdio.h>
#include <unistd.h>
int main()
{
int cnt = 10;
while(cnt)
{
printf("%d\r", cnt--);
fflush(stdout);
sleep(1);
}
return 0;
}
回车 \r
我们可以看到在输出下一个数之前都让光标先回到本行首格。
但是为什么输出效果和我预想的完全不一样?
https://img-blog.csdnimg.cn/direct/6f324e9b0b3c4f95b204b13ebcc00b8e.png
printf("%-2d\r", cnt--);
我们以两位字符进行输出,-则是表示靠左对齐,就可以正常输出了!
3. 进度条
在进行上面的铺垫之后,我们开始编写我们的第一个小程序。我们将用两个源文件和一个头文件,一个说明,一个调用,一个实现
test.c:实现
test.h:说明
main.c:调用
// Makefile:
mytest:test.c main.c
gcc -o $@ $^
.PHONY:clean
clean:
rm -rf mytest
3.1 版本一
在版本一中,我们只要简单实现一下基本的功能,得到一个基本框架就足够了。
// process_v1
//test.h:申明
pragma once
#include <stdio.h>
#include <string.h>
#include <unistd.h>
// 定义进度条的总长度,因为有'\0'的存在所以设为101
#define SIZE 101
// 定义进度条的当前进度
#define MAX_RATE 100
// 进度条的符号
#define STYLE '#'
// 进度条的休眠时间
#define STIME 1000*15
void process_v1();
.............
//test.c:实现
#include "test.h"
// 旋转光标
const char *str = "|/-\\";
// \\:才能表示一个'\'
void process_v1()
{
int rate = 0;
//初始化进度条全为'\0'
char bar = {0};
//循环打印
int num = strlen(str);
while(rate <= MAX_RATE)
{
// 进度条的打印格式
// -100:先取好[]的范围,然后靠左打印。
printf("[%-100s][%d%%][%c]\r", bar, rate, str);
// 刷新缓冲区
fflush(stdout);
// 休眠时长
usleep(STIME);
// 填充符号
bar = STYLE;
}
// 刷新
printf("\n");
}
.............
//main.c:调用
#include "test.h>
int main()
{
process();
return 0;
}
进度条:版本一
我们的第一代进度条也就完成了,实现了基本的结构框架!而我们的进度条,肯定不能干自己的,一定是和某种使命关联起来的!
3.2 版本二
我们将循环改成内部维护一个简单的静态缓冲区,每次往缓冲区里面增加内容然后刷新缓冲区内容就可以
不能一次将进度条打印完毕,否则不能与场景更好的联合
// process_v2
//test.h:申明
#pragma once
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define SIZE 101
#define MAX_RATE 100
#define STYLE '#'
#define STIME 1000*15
typedef void(*callback_t)(int); // 回调函数
// 这里我们也可以使用函数指针
void process_v2(int);
~
.............
//main.c:调用
#include "test.h"
#define TARGET_SIZE 1024*1024 // 模拟下载软件的大小
#define DSIZE 1024*10 // 模拟下载的速度
//void download()
//{
// int target = TARGET_SIZE; // 软件总体积
// int total = 0; // 当前下载的大小
//
// while(total < target)
// {
// usleep(STIME); // 用休眠时间,模拟下载时间
// total += DSIZE;
// process_v2(total*100/target);
// }
// printf("\n");
//}
// 回调函数
void download(callback_t cb)
{
int target = TARGET_SIZE; // 软件总体积
int total = 0; // 当前下载的大小
while(total < target)
{
usleep(STIME); // 用休眠时间,模拟下载时间
total += DSIZE;
int rate = total*100/target;
cb(rate);
}
printf("\n");
}
int main()
{
download(process_v2);
return 0;
}
.............
//test.c:实现
#include "test.h"
const char *str = "|/-\\";
void process_v2(int rate)
{
static char bar = {0};
int num = strlen(str);
if(rate <= MAX_RATE && rate >= 0)
{
printf("[%-100s][%d%%][%c]\r", bar, rate, str);
fflush(stdout);
bar = STYLE;
}
if(rate == MAX_RATE)
{
// 重新刷新为0
memset(bar, '\0', sizeof(bar));
}
}
进度条:版本二
我们也能完成进度条的实现,最后我们在优化一下,变成我们的版本三!。
3.3 版本三
因为版本二已经能将进度条完美的出现了,我们版本三,只是在二的底子上,美化一下,所以只是简单修改一点代码!
https://img-blog.csdnimg.cn/direct/49ef7ebf9168438e8b58ab42d9aa1de9.png
// test.h
#define STYLE_DEADER '>'
#define STYLE_BODY '='
typedef void (*callback_t)(double);
.............
// main.c
// 我们在下载时,模拟下载中断的状态
void download(callback_t cb)
{
int target = TARGET_SIZE; // 软件总体积
int total = 0; // 当前下载的大小
while(total <= target)
{
usleep(STIME); // 用休眠时间,模拟下载时间
total += DSIZE;
double rate = total*100/target;
// 我们让下载进度永远维持在50%左右
if(rate > 50.0)
{
total = target/2;
}
cb(rate);
}
printf("\n");
}
.............
// test.c
if(rate <= MAX_RATE && rate >= 0)
{
// 设置cnt是为了在下载终止时,光标依然能变化
cnt++;
cnt = cnt > num ? 0 : cnt;
// \033[1;47;30m ... \033[0m 则是更改输出时字体和背景颜色
printf("加载中...\033[%.1lf%%][%c]\r", bar, rate, str);
fflush(stdout);
if(rate < MAX_RATE)
{
bar[(int)rate] = STYLE_BODY;
bar[(int)rate+1] = STYLE_HEADER;
}
else{
bar[(int)rate] = STYLE_BODY;
}
}
进度条:版本三
我们可以发现,我们修改了字体颜色和配景,设置测试了大概碰到的中断情况,光标依旧会变革。当然了进度条另有许多情景,等候着各位开发!
4. 总结拓展
拓展:
关于print带颜格式化输出,我在这里推荐一篇博客,有兴趣的可以去了解一下
print带颜格式化输出
总结:
本篇我们简单了解了一下缓冲区,以及换行'\n'与回车'\r'的基本概念,然后由浅入深的先容了三个版本的进度条,当然了美化方式各位都不一样,都是可以的,我们的Linux第一个小程序就讲到这里
谢谢大家支持本篇到这里就竣事了
https://img-blog.csdnimg.cn/direct/c37b88b7b23242c5853896c9b0630662.gif#pic_center
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]