您的位置:首页 > 新闻 > 会展 > Liunx 小程序之进度条

Liunx 小程序之进度条

2024/10/7 2:07:47 来源:https://blog.csdn.net/2302_77289177/article/details/140898053  浏览:    关键词:Liunx 小程序之进度条

Liunx 小程序之进度条

  • 效果
  • 前提条件
    • 回车和换行
    • 缓冲区
      • 倒计时
  • 进度条
    • 纯进度条
    • 模拟下载的进度条
      • Progressbar.h
      • Progressbar.c
      • main.c
      • makefile

效果

先来看效果,这其实是一个动态的进度条,后有源码,运行即可:

在这里插入图片描述

在这里插入图片描述

前提条件

在制作之前有两个前提条件需要了解

回车和换行

这个概念,一般人均会混为一谈,而程序员因为熟知 '\n' ,所以深刻理解 换行符将当前光标位置换到下一行的开头

'\n' 这个字符其实是两个动作,一个是 回车 ,一个是 换行

  • 换行:顾名思义,只是将当前光标位置换进下一行,但是其在下一行的什么位置,取决于之前上一行的所在位置
  • 回车:这是 将光标置于此行开头位置

所以一般来说, 换行符 所完成的是这 两个动作 的总和

而在 C 语言里,只 回车'\r' ,所以有些人会写出 "\r\n" 这样的代码,这时候的 '\n' 就只表示 换行

缓冲区

有了上面 回车换行 的解释,对于 缓冲区 ,我们需要对比观察这样两份代码:

// 第一份代码:
#include <stdio.h>
#include <unidstd.h>
int main()
{printf("Hello World...\n");sleep(3);return 0;
}
// 第二份代码:
#include <stdio.h>
#include <unidstd.h>
int main()
{printf("Hello World...");sleep(3);return 0;
}

不同之处 仅在于代码 printf("Hello World..."); 打印的字符串是否含有 '\n' 换行符

那么请将这两份代码放在命令行终端进行验证,分别编译运行后,眼睛看到的结果将不一样

  1. 第一份会将 Hello World... 打印出来并空出一行,休眠 3 秒
  2. 第二份会先休眠 3 秒,再打印出 Hello World... 这时由于没有 换行符,下一个 命令行提示符 会紧跟字符串打印出来

请注意,这是肉眼观察到的结果,那为什么第二份代码肉眼观察是先休眠呢?

首先我们知道,C 语言对上面的两份代码一定是 顺序执行 的,也就是说 均为先打印,后休眠 ,既如此,那第二份代码的字符串为何等休眠后才出现呢?真正的字符串又被打印在了哪里?

首先,缓冲区可以看作是内存里的一块空间; printf 函数也并不是把字符串直接显示在显示器屏幕上,而是将字符串拷贝进这块缓冲区,再由缓冲区刷新到显示器屏幕上

第二段程序由于没有 '\n',会将字符串一直放在缓冲区里,直到程序结束,自动冲涮缓冲区时才被刷新到屏幕上

目前来说 缓冲区的刷新策略是:

  1. 含有 '\n' ,会将 '\n' 前面所有的内容都刷新出来(行刷新)
  2. 缓冲区满即刷新
  3. 使用函数 fflush(stdout); 强制刷新

倒计时

有了上面的解释,咱就可以先着手写一个 倒计时 ,代码如下:

// pre-test.c 源文件
#include <stdio.h>
#include <unistd.h>
int main()
{for (int i = 10; i >= 0; --i){printf("倒计时:%2d\r", i);fflush(stdout);sleep(1);}printf("\n");return 0;
}
# makefile 文件
bin=pre-test
src=pre-test.c$(bin):$(src)gcc $^ -o $@ -std=c99.PHONY:clean
clean:rm -f $(bin)

试一试咯 ^ ^

进度条

纯进度条

我们先完成一个 纯进度条 的代码:

#define Length 101
#define Style '#'
const char* lable = "|/-\\";void ProsBar()
{char bar[Length];memset(bar, '\0', sizeof(bar));int cnt = 0;int len = strlen(lable);while (cnt <= 100){printf("[%-100s][%3d%%][%c]\r", bar, cnt, lable[cnt % len]);fflush(stdout);bar[cnt++] = Style;usleep(20000);}printf("\n");
}

如果能看懂前面 倒计时 的代码,那这里的代码也就可以看懂了,原理都一样,如果运行你会发现,这是个自主加载的进度条,不表示任何事物的进度,那怎么行,接下来我们模拟 下载的进度条

模拟下载的进度条

只要将 纯进度条 看懂,那接下来的代码也一定可以看懂,其实原理和 倒计时 一样,代码不做解释

下面我将把代码写成结构化形式,利用 make 自动化构建

Progressbar.h

#pragma once #include <stdio.h> 
#include <unistd.h> // 定义函数指针,用于回调函数
typedef void(* callback_t)(double, double);void ProsBar(double total, double current);

Progressbar.c

#include "Progressbar.h" 
#include <string.h> #define Length 101
#define Style '#'const char* lable = "|/-\\";void ProsBar(double total, double current)
{static char bar[Length] = { 0 };// memset(bar, '\0', sizeof(bar));static int cnt = 0;int len = strlen(lable);double rate = (current * 100.00) / total;int loop_count = (int)rate;while (cnt <= loop_count){bar[cnt++] = Style;// usleep(10000);}printf("[%-100s][%.2lf%%][%c]\r", bar + 1, rate, lable[(cnt - 1) % len]);fflush(stdout);if (cnt >= 100){cnt = 0;memset(bar, '\0', sizeof(bar));}
}

main.c

#include "Progressbar.h" void Download_Simulation(callback_t cb)
{double FileSize = 100 * 1.0;  // 文件大小double Current = 0.0;         // 下载进度double BandWidth = 1.0;       // 网络带宽printf("Download start!\n");while (Current <= FileSize){cb(FileSize, Current);Current += BandWidth;usleep(50000);}printf("\nThe file size is %.2lf MB\nDownload complete!\n", FileSize);
}int main()
{// 回调函数Download_Simulation(ProsBar);return 0;
}

makefile

bin=Progressbar 
src=main.c Progressbar.c$(bin):$(src)gcc $^ -o $@.PHONY:clean
clean:rm -f $(bin)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com