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

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




一、预备知识

📒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;
}

🎁结语:

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

相关文章
|
1月前
|
缓存 小程序 Linux
【Linux】Linux第一个小程序-进度条
【Linux】Linux第一个小程序-进度条
|
25天前
|
存储 Ubuntu Linux
制作一个嵌入式Linux的应用程序升级文件
制作一个嵌入式Linux的应用程序升级文件
12 2
|
1月前
|
算法 Linux 调度
根基已筑!Anolis OS 23.1 预览版本搭载 Linux 6.6 内核和工具链升级完成
Anolis OS 23.1 对软件包的选择和组合进行了重新规划与决策,满足更为广泛的应用场景需求。
|
1月前
|
存储 缓存 供应链
『Linux升级路』冯诺依曼体系结构与操作系统
『Linux升级路』冯诺依曼体系结构与操作系统
|
1月前
|
NoSQL Linux 编译器
『Linux升级路』基础开发工具——gdb篇
『Linux升级路』基础开发工具——gdb篇
|
1月前
|
Linux 编译器 开发工具
『Linux升级路』基础开发工具——make/Makefile篇
『Linux升级路』基础开发工具——make/Makefile篇
|
15天前
|
小程序 前端开发 API
小程序全栈开发中的多端适配与响应式布局
【4月更文挑战第12天】本文探讨了小程序全栈开发中的多端适配与响应式布局。多端适配涉及平台和设备适应,确保统一用户体验;响应式布局利用媒体查询和弹性布局维持不同设备的布局一致性。实践中,开发者可借助跨平台框架实现多平台开发,运用响应式布局技术适应不同设备。同时,注意兼容性、性能优化和用户体验,以提升小程序质量和用户体验。通过这些方法,开发者能更好地掌握小程序全栈开发。
|
15天前
|
小程序 前端开发 API
微信小程序全栈开发中的异常处理与日志记录
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中的异常处理和日志记录,强调其对确保应用稳定性和用户体验的重要性。异常处理涵盖前端(网络、页面跳转、用户输入、逻辑异常)和后端(数据库、API、业务逻辑)方面;日志记录则关注关键操作和异常情况的追踪。实践中,前端可利用try-catch处理异常,后端借助日志框架记录异常,同时采用集中式日志管理工具提升分析效率。开发者应注意安全性、性能和团队协作,以优化异常处理与日志记录流程。
|
15天前
|
小程序 安全 数据安全/隐私保护
微信小程序全栈开发中的身份认证与授权机制
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中的身份认证与授权机制。身份认证包括手机号验证、微信登录和第三方登录,而授权机制涉及角色权限控制、ACL和OAuth 2.0。实践中,开发者可利用微信登录获取用户信息,集成第三方登录,以及实施角色和ACL进行权限控制。注意点包括安全性、用户体验和合规性,以保障小程序的安全运行和良好体验。通过这些方法,开发者能有效掌握小程序全栈开发技术。
|
15天前
|
小程序 前端开发 安全
小程序全栈开发中的跨域问题及其解决方案
【4月更文挑战第12天】本文探讨了小程序全栈开发中的跨域问题及其解决方案。跨域问题源于浏览器安全策略,主要体现在前后端分离、第三方服务集成和数据共享上。为解决此问题,开发者可采用CORS、JSONP、代理服务器、数据交换格式和域名策略等方法。实践中需注意安全性、兼容性和性能。通过掌握这些解决方案,开发者能更好地处理小程序的跨域问题,提升用户体验。