『Linux升级路』进度条小程序

🔥博客主页:小王又困了

📚系列专栏:Linux

🌟人之为学,不日近则日退

❤️感谢大家点赞👍收藏⭐评论✍️


目录

一、预备知识

📒1.1缓冲区

📒1.2回车和换行

二、倒计时

📒2.1源代码

📒2.2注意事项

三、进度条

📒3.1源代码

📒3.2实际应用


一、预备知识

📒1.1缓冲区

我们先观察两段代码的现象:

#include <stdio.h>
#include <unistd.h>
int main() 
{
    printf("Hello Linux!\n");                                                                                                                                                   
                                                                                                                                                                                              
    sleep(3);
    return 0;
}

 这段代码先执行printf函数,在屏幕上打印出Hellow Linux!,然后执行sleep函数让函数休眠3秒,最后程序结束。

#include <stdio.h>
#include <unistd.h>
int main() 
{
    printf("Hello Linux!");                                                                                                                                                   
                                                                                                                                                                                              
    sleep(3);
    return 0;
}

 通过上图我们可以看到,当我们去掉 ‘\n’ 对代码进行编译,程序先休眠了3秒,然后在屏幕上打印Hellow Linux!。由于去掉了‘\n’ ,也没有换行。

📝现象分析:

      看到上面的现象,大家一定会有很大的疑惑。难道程序是先执行了sleep函数,然后再去执行printf函数。这样的猜想是错误的,任何一个C语言程序,没有遇到选择和循环语句,都要严格按照顺序结构去执行,代码都是从上到下依次执行。所以一定是先执行printf函数,再执行sleep函数。那在休眠的3秒里,Hellow Linux!去了哪里呢?代码被保存在了缓冲区中,默认当程序结束的时候才会将缓冲区中的内容刷新出来,带 \n 就是要求把缓冲区的的数据立即刷新到显示器上。

  • 缓冲区是一种用于临时存储数据的区域,通常用于临时保存数据以平衡数据处理速度不匹配的情况。 

📒1.2回车和换行

     回车和换行是两个与文本文件和文本编辑有关的控制字符,它们在不同的操作系统和编程环境中可能有不同的表现。

📝回车:将光标移动到当前行的开始(最左侧)

  • 表示为ASCII字符 \r
  • 在打字机时代,回车的原意是将打印头移动到行首,以便在同一行上写入新的文本。
  • 在计算机中,回车通常表示将光标移动到当前行的开头,但不换行到新的一行。

📝换行:将光标水平方向保持不变,竖直方向向下平移一行。

  • 表示为ASCII字符 \n
  • 在打字机时代,换行的原意是将纸向上移动一行,以便在新的行上写入文本。
  • 在计算机中,换行通常表示将光标移动到下一行的开头。

二、倒计时

📒2.1源代码

 学习了上面的知识,我们可以写一个倒计时的小程序。

📖源代码

#include <stdio.h>
#include <unistd.h>

int main()
{
    int cnt=9;
    while(cnt>=0)
    {
        printf("%d\r",cnt);
        sleep(1);
        cnt--;
    }
    printf("\n");
    return 0;
}

📖效果演示

如上图,运行我们的程序,却没有想要的倒计时效果,这是因为我们没有刷新缓冲区,执行的结果都存放在缓冲区 。我们要使用fflush接口来刷新缓存区。

📝刷新缓冲区

任何一个C程序运行的时候都会默认帮我们打开以下三个流:

  • stdin —— 标准输入流(键盘)
  • stdout —— 标准输出流(显示器)
  • stderr —— 标准错误(显示器)

这三个流都是FILE*的指针,所以任何一个C程序运行的时候,操作系统会帮我们打开以上三个文件。我们只需要看stdout标准输出流,使用fflush接口刷新。

📖源代码

#include <stdio.h>
#include <unistd.h>
int main()
{
    int cnt = 9;
    while(cnt >= 0)
    {
        printf("%-2d\r",cnt);
        fflush(stdout);
        sleep(1);
        cnt--;
    } 
    printf("\n");                                                                                                                                                                         
    return 0;
}

 📖效果演示

📒2.2注意事项

📝格式化控制

     我们需要知道,往显示器上打印整型10,本质上是打印了字符1和字符0。因此打印10,会占用两个字符,而打印0~9只需要一个字符,所以 \r 回车之后只会覆盖一个字符,对第二个字符0始终没有影响,因此我们需要用%-2d来控制,每次打印两个位宽的字符, - 表示将这两个字符左对齐。如果不进行格式化控制,打印出来的结果将是下面这样:

三、进度条

📒3.1源代码

     我们实现的进度条进度条除了有进度的推进,还要有百分比提示和转动提示。

📖processBar.h

#pragma once
#include <stdio.h>
#include <unistd.h>
#include <string.h>

#define NUM 103
#define BODY '='
#define HEAD '>'  

void processbar();

📖processBar.c

#include "processbar.h"//引用头文件
const char* lable = "|/-\\";//转动提示
void processbar()
{
    char bar[NUM];
    int cnt=0;
    memset(bar,'\0',sizeof(bar));

    int len=strlen(lable);
    bar[cnt]=HEAD;

    while(cnt<=100)
    {
        printf("[%-100s][%d%%][%c]\r",bar,cnt,lable[cnt%len]);
        fflush(stdout);
        bar[cnt++]=BODY;
        if(cnt<100)
        {
            bar[cnt]=HEAD;                                                                                                                                
        }
        usleep(100000);
    }
    printf("\n");
}

📒3.2实际应用

     上面的代码只是演示进度条的原理,但是在实际中,进度条并不是这样用的。以下载东西为例,作为一个进度条,它本身并不知道下载了多少,它只会提供一个接口,在下载东西的时候,调用这个接口,然后将已经下载好的比率作为参数传给进度条模块,它会根据比率打印出对应的进度条样式。

📖processBar.h

#pragma once
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>

#define NUM 103
#define BODY '='
#define HEAD '>'  

typedef void (*callback_t)(double);

void process_flush(double rate);

📖processBar.c

#include "processbar.h"//引用头文件
const char* lable = "|/-\\";//转动提示

char buffer[NUM] = {0};
void process_flush(double rate)
{
    static int cnt = 0;
    int n = strlen(lable);
    if(rate <= 1.0) buffer[0] = Head;
    printf("[\033[4;32;44m%-100s\033[0m][%.1f%%][%c]\r", buffer, rate, lable[cnt%n]);
    fflush(stdout);

    buffer[(int)rate] = Body;
    if((int)rate+1 < 100) buffer[(int)(rate+1)] = Head;
    if(rate>=100.0) printf("\n");

    cnt++;
    cnt%=n;
}

📖main.c

void download(callback_t cb) // 回调函数的形式
{
    srand(time(NULL)^1023);
    int total = FILESIZE;
    while(total)
    {
        usleep(10000); //下载动作
        int one = rand()%(1024*1024*10);
        total -= one;
        if(total < 0) total = 0;

        // 当前的进度是多少?
        int download = FILESIZE - total;
        double rate = (download*1.0/(FILESIZE))*100.0; // 0 23.4 35.6, 56.6
        cb(rate);
        //process_flush(rate);
        //printf("download: %f\n", rate); // rate出来了,应该让进度条刷新
    }
}

int main()
{
    download(process_flush);
    return 0;
}


🎁结语: 

     本次的内容到这里就结束啦。希望大家阅读完可以有所收获,同时也感谢各位读者三连支持。文章有问题可以在评论区留言,博主一定认真认真修改,以后写出更好的文章。你们的支持就是博主最大的动力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/230686.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

pair的用法,详解

1.pair是什么 pair名为二元组&#xff0c;顾名思义&#xff0c;就是储存二元组的。 2.pair的初始化 pair<第一个值类型, 第二个值类型> pr 第一个值类型&#xff1a;要储存的第一个值的数据类型第二个值类型&#xff1a;要储存的第二个值的数据类型pair<int, int&g…

【数据结构】单调栈与单调队列算法总结

单调栈 知识概览 单调栈最常见的应用是找到每一个数离它最近的且比它小的数。单调栈考虑的方式和双指针类似&#xff0c;都是先想一下暴力做法是什么&#xff0c;然后再挖掘一些性质如单调性&#xff0c;最终可以把目光集中在比较少的状态中&#xff0c;从而达到降低时间复杂…

让聪明的车连接智慧的路,C-V2X开启智慧出行生活

“聪明的车 智慧的路”形容的便是车路协同的智慧交通系统&#xff0c;从具备无钥匙启动&#xff0c;智能辅助驾驶和丰富娱乐影音功能的智能网联汽车&#xff0c;到园区的无人快递配送车&#xff0c;和开放的城市道路上自动驾驶的公交车、出租车&#xff0c;越来越多的车联网应用…

【vSphere | VM】虚拟机自定义规范Ⅲ —— 创建 Linux 虚拟机自定义规范

目录 4. 创建关于Linux系统的虚拟机自定义规范4.1 新建 Linux 虚拟机自定义规范&#xff08;1&#xff09;名称和目标操作系统&#xff08;2&#xff09;计算机名称&#xff08;3&#xff09;时区&#xff08;4&#xff09;自定义脚本&#xff08;5&#xff09;网络&#xff08…

CleanMyMac X清理垃圾软件有哪些功能?2024版本更新啥内容

如今电脑成为大多数人工作的工具&#xff0c;使用得越久就越需要清理垃圾软件。系统垃圾、废纸娄垃圾、大型和旧文件这些通常都占用了我们的电脑几G的空间。 想要清除不必要的垃圾文件&#xff0c;可以使用mac卸载软件CleanMyMac X&#xff0c;这款清理垃圾软件可以智能扫描Ma…

电脑待机怎么设置?让你的电脑更加节能

在日常使用电脑的过程中&#xff0c;合理设置待机模式是一项省电且环保的好习惯。然而&#xff0c;许多用户对于如何设置电脑待机感到困扰。那么电脑待机怎么设置呢&#xff1f;本文将深入探讨三种常用的电脑待机设置方法&#xff0c;通过详细的步骤&#xff0c;帮助用户更好地…

EXP-00056: 遇到 ORACLE 错误 12154 ORA-12154: TNS: 无法解析指定的连接标识符

exp oas/oasoas filed:\daochu.dmp owner(s) 导出特定用户 //exp 用户名/密码数据库 filed:\daochu.dmp owner(用户名) 1.重启oracle监听 cmd 中输入 services.msc 找到服务&#xff1a;OracleOraDb10g_home1TNSListener 与 OracleServiceORCL。 把两个服务启动. 若未解决…

JavaScript 条件语句之switch

if..else虽然有多条路选择&#xff0c;但是代码读起来会很累人&#xff0c;说白了就是使用switch来简化if else表达式。 语法会有switch关键字&#xff0c;case关键字&#xff0c;以及break关键字。需要注意的是&#xff0c;每个case代码块内部的break语句不能少&#xff0c;否…

【抽象策略模式】实践

前言 刚果商城&#xff0c;用户登录 Or 注册 发送邮箱验证码场景&#xff0c;使用抽象策略模式实现 什么是抽象策略模式 抽象策略模式是一种行为型设计模式&#xff0c;它允许定义一系列算法&#xff0c;将每个算法封装起来&#xff0c;并使它们可以互相替换。这使得客户端代码…

EMC VNX Unified存储NAS控制台常见问题解答

每次遇到VNX unfied的case就是一坨屎&#xff0c;很多客户根本不理解什么是Unifed storage&#xff0c;EMC的Clariion中端存储系统还分Block和Unified的产品。这个blog就是简单介绍一下VNX Unified存储的管理控制台&#xff0c;英文是 control station, 简称为CS。 顾名思义&a…

Kubernetes集群安装高可用postgresql

Kubernetes集群安装高可用postgresql Bitnami 提供的 postgresql-ha 解决方案是一个预配置的、高可用的 PostgreSQL 集群配置&#xff0c;通常部署在 Kubernetes 环境中。它使用了一些关键技术和组件来实现数据库的高可用性。&#xff0c;Bitnami postgresql-ha 主要采用以下构…

JVM 性能调优及监控诊断工具 jps、jstack、jmap、jhat、jstat、hprof 使用详解

目录 一. 前言 二. jps&#xff08;Java Virtual Machine Process Status Tool&#xff09; 三. jstack 四. jmap&#xff08;Memory Map&#xff09;和 jhat&#xff08;Java Heap Analysis Tool&#xff09; 五. jstat&#xff08;JVM统计监测工具&#xff09; 六. hpro…

云原生的 CI/CD 框架tekton - pipeline(一)

文章目录 1. 官方介绍2. 组件2.1 Tekton Pipelines2.2 部署pipeline2.3 部署dashborad2.3.1 task2.3.2 taskrun2.3.3 Pipeline2.3.4 PipelineRun 3. 案例案例1: 拉取代码并查看readmestep1: 创建task - 拉取代码step2: 创建task - 查看reamdestep3: 创建task的编排 - pipelines…

深入理解CyclicBarrier

文章目录 1. 概念2. CylicBarier使用简单案例3. 源码 1. 概念 CyclicBarrier 字面意思回环栅栏&#xff08;循环屏障&#xff09;&#xff0c;通过它可以实现让一组线程等待至某个状态&#xff08;屏障点&#xff09;之后再全部同时执行。叫做回环是因为当所有等待线程都被释放…

智能优化算法应用:基于法医调查算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于法医调查算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于法医调查算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.法医调查算法4.实验参数设定5.算法结果6.参考…

Unity 状态系统

状态系统 原理食用方法Demo 原理 #mermaid-svg-lUbxJ8eMP3KqrEhY {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-lUbxJ8eMP3KqrEhY .error-icon{fill:#552222;}#mermaid-svg-lUbxJ8eMP3KqrEhY .error-text{fill:#55…

使用RSA工具进行对信息加解密

我们在开发中需要对用户敏感数据进行加解密&#xff0c;比如密码 这边科普一下RSA算法 RSA是非对称加密算法&#xff0c;与对称加密算法不同;在对称加密中&#xff0c;相同的密钥用于加密和解密数据,因此密钥的安全性至关重要;而在RSA非对称加密中&#xff0c;有两个密钥&…

一文说清google最新大模型Gemini

随着AI技术的快速发展&#xff0c;谷歌和其他科技巨头在研究和部署上的竞争也越来越激烈。本月12月6号谷歌CEO哈萨比斯在谷歌官网发文&#xff0c;宣布推出万众瞩目的多模态大模型Gemini。标题明晃晃写着“最大”、“最强”&#xff0c;主打的就是一个干爆GPT-4。 一、Gemini的…

unity 2d 入门 飞翔小鸟 场景延续(八)

1、新建c#脚本如下 代码&#xff0c;在前方生成生成自身图片并3s后销毁自身&#xff0c;在碰撞物体后小鸟死亡后不删除自身 using System.Collections; using System.Collections.Generic; using UnityEngine;public class CopyScene : MonoBehaviour { //要复制的对象public…

银行卡二要素API的应用案例:从在线购物到金融投资

引言 随着互联网技术的不断发展&#xff0c;人们的金融需求也在不断增加。随之而来的是各种新型金融服务的涌现&#xff0c;让用户的金融体验更加便利快捷。其中&#xff0c;银行卡二要素API的应用&#xff0c;则为用户的金融体验和安全性提供了极大的保障。 银行卡二要素API…