【Linux】使用Linux实现小程序 - 进度条

是阿建吖! 2024-09-05 11:07:02 阅读 55

在这里插入图片描述

目录

一、缓冲区二、回车换行的概念三、进度条的设计3.1 版本1(没有配合场景)3.2 版本2(配合场景)3.3 版本3(美化进度条)

结尾

一、缓冲区

C/C++语言,会针对标准输出,给我们提供默认的缓冲区,这里主要讲输出缓冲区,那么它在哪里呢?

在C语言中,输出缓冲区通常与标准I/O流(如stdout、stderr等)相关联。这些流在C标准库中通过FILE结构体来表示,而FILE结构体内部封装了文件描述符和缓冲区等信息。因此,当使用printf()等函数进行输出时,实际上是将数据写入到了与stdout流相关联的缓冲区中。

在这里插入图片描述

那么需要怎么证明呢?

当我们没有使用fflush刷新缓冲区时,printf()函数早已运行了,但是数据却没有立马显示出来,而是暂停了两秒钟才显示出来,因为printf()函数输出的数据在缓冲区中,所以没有立马显示出来,当暂停两秒钟后,程序结束,强制刷新缓冲区,才将缓冲区的内容输出。

在这里插入图片描述

那么有人也会问了,当我们使用 printf()函数输出数据时添加<code>\n,也能立马输出数据这是为什么?

因为/n也是一种刷新策略,/n也叫做行刷新。


二、回车换行的概念

在这里向大家提一个问题,大家是否认为回车和换行是一个东西,其实不然,回车和换行是两个不同的概念,回车是将光标移回当前行的第一个位置,换行是将光标的位置移动到下一行,但光标的位置并不会移回行的第一个位置

在这里插入图片描述

在老式键盘中的回车换行也是比较形象的体现了回车和换行的特征。

在这里插入图片描述

那么我们在敲代码使用的 <code>/r 和 /n 分别是什么呢?

- /r 是回车,光标仅仅回到当前行的第一个位置。

- /n 是回车换行,光标即移回行的第一个位置,又移动到下一行。

在这里插入图片描述

那么下面写一份代码,除<code>/r 和 /n不同外其他部分全部相同,来看看程序的结果分别是什么。

在这里插入图片描述

在这里插入图片描述

我们通过上面的图片可以看到使用<code>/n时,每一秒钟在下一行输出一个数字

而使用/r时,每一秒钟在当前行输出一个数字,并且覆盖上一个字符,最终被命令行覆盖,但是当循环时强制刷新缓冲区就可以把最后一个数字留下来,通过/r的这个特性,那么我们就可以设计倒计时,进度等。


三、进度条的设计

3.1 版本1(没有配合场景)

在这里插入图片描述

进度条效果图

在这里插入图片描述

<code>// process.c

#include"process.h"

const char rotate[]={ -- -->"|/-\\"};

void process()

{

char arr[SIZE] = { 0};

int rate = 0;

int len = strlen(rotate);

while(rate <= MAX_RATE)

{

printf("[%-100s][%3d%%][%c]\r",arr,rate,rotate[rate%len]);

usleep(STIME);

arr[rate++]=STYLE;

}

printf("\n");

}

//process.h

#include<stdio.h>

#include <unistd.h>

#include<string.h>

#define STYLE '#' // 进度条的风格

#define MAX_RATE 100 // 进度的最大值

#define SIZE 101 // 数组需要开多大

#define STIME 1000*50 // 暂停的时间

void process();

//main.c

#include"process.h"

int main()

{

process();

return 0;

}

// Makefile

cc=gcc

src=main.c process.c

target=myprocess

$(target):$(src)

$(cc) $^ -o $@

.PHONY:clean

clean:

rm -f $(target)


3.2 版本2(配合场景)

无论任何进度条,一定和某种任务关联,那么这个版本的进度条不是在函数内部循环打印,而是通过回调的方式来进行某种任务的通知,动态进行更新进度条。

在这里插入图片描述

<code>// process.c

#include"process.h"

const char rotate[]={ -- -->"|/-\\"};

void process2(int rate)

{

static char arr[SIZE] = { 0};

int len = strlen(rotate);

if(rate <= MAX_RATE && rate >= 0)

{

printf("[%-100s][%3d%%][%c]\r",arr,rate,rotate[rate%len]);

fflush(stdout);

arr[rate]=STYLE;

}

}

// main.c

#include"process.h"

#define TOTAL_SIZE 1024*1024 // 程序大小

#define DSIZE 1024*10 // 下载速度

void download()

{

int target = TOTAL_SIZE;

int sum = 0; // 当前下载总大小

while(sum <= TOTAL_SIZE)

{

int rate = sum*100/target;

process2(rate);

sum += DSIZE;

usleep(STIME);

}

process2(MAX_RATE);

printf("\n");

}

int main()

{

download();

return 0;

}

//process.h

#include<stdio.h>

#include <unistd.h>

#include<string.h>

#define STYLE '#' // 进度条的风格

#define MAX_RATE 100 // 进度的最大值

#define SIZE 101 // 数组需要开多大

#define STIME 1000*50 // 暂停的时间

typedef void(*callback_t)(int);

void process1();

void process2(int);


3.3 版本3(美化进度条)

上面两个版本进度条中的旋转光标会受到进度的影响,在生活中下载软件、游戏等应用的时候可能在某个进度的时候突然卡住了,如果旋转光标会受到进度的影响的话,就不能知道软件是否在下载,所以当前版本对当前问题进行了优化,使旋转光标不再受到进度的影响。并且将进度的显示修改为小数。

在这里插入图片描述

进度条效果图

在这里插入图片描述

<code>#include"process.h"

const char rotate[]={ -- -->"|/-\\"};

void process3(double rate)

{

static int rotate_cnt = 0;

static char arr[SIZE] = { 0};

int len = strlen(rotate);

rotate_cnt = ++rotate_cnt % len;

if(rate < MAX_RATE && rate > 0)

{

arr[(int)rate-1]=STYLE_BODY;

arr[(int)rate]=STYLE_HEAD;

}

else if(rate == MAX_RATE)

{

arr[(int)rate]='\0';

arr[(int)rate-1]=STYLE_BODY;

}

printf("[%-100s][%6.2lf%%][%c]\r",arr,rate,rotate[rotate_cnt%len]);

fflush(stdout);

}

//main.c

#include"process.h"

#define TOTAL_SIZE 1024*1024 // 程序大小

#define DSIZE 1024*10 // 下载速度

void download(callback_t cb)

{

int target = TOTAL_SIZE;

int sum = 0; // 当前下载总大小

while(sum <= TOTAL_SIZE)

{

double rate = sum*100.0/target;

cb(rate);

sum += DSIZE;

usleep(STIME);

}

cb(MAX_RATE);

printf("\n");

}

int main()

{

download(process3) ;

return 0;

}

// process.h

#include<stdio.h>

#include <unistd.h>

#include<string.h>

#define STYLE '#' // 进度条的风格

#define MAX_RATE 100 // 进度的最大值

#define SIZE 101 // 数组需要开多大

#define STIME 1000*50 // 暂停的时间

#define STYLE_HEAD '>'

#define STYLE_BODY '='

// typedef void(*callback_t)(int);

typedef void(*callback_t)(double);

void process1();

void process2(int);

void process3(double);


结尾

如果有什么建议和疑问,或是有什么错误,大家可以在评论区中提出。

希望大家以后也能和我一起进步!!🌹🌹

如果这篇文章对你有用的话,希望大家给一个三连支持一下!!🌹🌹

在这里插入图片描述



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。