当前位置: 首页 > news >正文

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)

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 急需一个加密软件,请问哪款安全性高且好用?
  • 数据要素流通交易的场景概述
  • Kubernets(k8s) 网络原理三:同主机内Pod相互访问
  • 安卓常用控件ListView
  • WSL介绍 安装 使用 高性能本地服务器【详细教程】
  • perl基础入门
  • 学习记录——day25 多线程编程 临界资源 临界区 竞态 线程的同步互斥机制(用于解决竟态)
  • 大数据技术复习--概述
  • 代码随想录算法训练营第二十四天| 455.分发饼干, 376. 摆动序列 , 53. 最大子序和
  • wps 最新 2019 专业版 下载安装教程,解锁全部功能,免费领取
  • 计算机网络-基于PIM-DM+IGMP的组播实验配置
  • ADAPT:动作感知驾驶字幕转换器
  • HTML-02.新浪新闻-标题-样式1
  • 技战法丨攻防演练防御——纵深、联动、诱捕(可搬运、可cv)
  • Python 获取企业微信中微盘的文件列表
  • 自己简单写的 事件订阅机制
  • 【跃迁之路】【444天】程序员高效学习方法论探索系列(实验阶段201-2018.04.25)...
  • 【跃迁之路】【733天】程序员高效学习方法论探索系列(实验阶段490-2019.2.23)...
  • 30天自制操作系统-2
  • bootstrap创建登录注册页面
  • Mocha测试初探
  • PHP 小技巧
  • SAP云平台里Global Account和Sub Account的关系
  • Spring Boot快速入门(一):Hello Spring Boot
  • SpringCloud集成分布式事务LCN (一)
  • SQLServer之创建数据库快照
  • 阿里云应用高可用服务公测发布
  • 安卓应用性能调试和优化经验分享
  • 关于 Linux 进程的 UID、EUID、GID 和 EGID
  • 巧用 TypeScript (一)
  • 入门级的git使用指北
  • 使用common-codec进行md5加密
  • 项目管理碎碎念系列之一:干系人管理
  • 小程序测试方案初探
  • 摩拜创始人胡玮炜也彻底离开了,共享单车行业还有未来吗? ...
  • # Apache SeaTunnel 究竟是什么?
  • #Datawhale AI夏令营第4期#多模态大模型复盘
  • #Z2294. 打印树的直径
  • (2022 CVPR) Unbiased Teacher v2
  • (附源码)ssm旅游企业财务管理系统 毕业设计 102100
  • (附源码)计算机毕业设计SSM疫情下的学生出入管理系统
  • (接上一篇)前端弄一个变量实现点击次数在前端页面实时更新
  • (三分钟)速览传统边缘检测算子
  • (深度全面解析)ChatGPT的重大更新给创业者带来了哪些红利机会
  • (十)【Jmeter】线程(Threads(Users))之jp@gc - Stepping Thread Group (deprecated)
  • (一)为什么要选择C++
  • (转)大型网站的系统架构
  • (转)德国人的记事本
  • (轉貼) UML中文FAQ (OO) (UML)
  • .NET WPF 抖动动画
  • .net获取当前url各种属性(文件名、参数、域名 等)的方法
  • .Net小白的大学四年,内含面经
  • /usr/bin/perl:bad interpreter:No such file or directory 的解决办法
  • @param注解什么意思_9000字,通俗易懂的讲解下Java注解
  • @RequestMapping处理请求异常