【Linux】简易进度条的实现

图片名称
🎉博主首页: 有趣的中国人

🎉专栏首页: Linux

🎉其它专栏: C++初阶 | C++进阶 | 初阶数据结构

在这里插入图片描述

小伙伴们大家好,本片文章将会讲解Linux进度条的实现的相关内容。


如果看到最后您觉得这篇文章写得不错,有所收获,麻烦点赞👍、收藏🌟、留下评论📝。您的支持是我最大的动力,让我们一起努力,共同成长!

文章目录

  • `1. 关于回车 & 换行`
  • `2. 简述缓冲区`
  • `3. 倒计时程序的编写`
  • `4. 简易进度条的实现`



1. 关于回车 & 换行



回车和换行是文本显示和处理的相关术语,我们常常认为这两个是同一概念,实则不然。


👨‍💻回车换行的概念


回车(Carriage Return)在打字机时代,回车指的是将打字机的打印头(称为"carrier")移回到行首的操作在计算机时代,回车通常表示将光标移动到当前行的开头而不会换到下一行。在ASCII字符集中,回车通常用"\r"表示。

换行(Line Feed):换行是指将光标移动到下一行的操作使得文本在纵向上向下移动一个行高。在ASCII字符集中,换行通常用"\n"表示。


在Unix和类Unix系统(如LinuxmacOS)中通常使用换行字符(“\n”)来表示换行。

在Windows系统中:通常使用回车和换行的组合来表示换行,即"\r\n"。



2. 简述缓冲区


缓冲区(Buffer)是计算机内存中的一块特定区域,用于临时存储数据。它在许多计算机系统和应用程序中发挥着重要作用,通常用于临时存储输入数据、输出数据或在内存和其他设备之间进行数据传输。

输入缓冲区:用于暂时存储从输入设备(如键盘、鼠标、网络接口等)接收到的数据,直到程序能够处理它们。输入缓冲区使得程序可以按需处理输入,而不必担心输入数据的速度与程序处理速度不匹配的问题

输出缓冲区:用于暂时存储将要发送到输出设备(如显示器、打印机、网络接口等)的数据,直到设备准备好接收它们。输出缓冲区可以提高数据传输的效率,因为程序不必等待设备就绪就可以继续执行。


👨‍💻缓冲区何时被清理

拿C语言举个例子:

在C语言中,标准库函数printf()用于将格式化的数据打印到标准输出流(通常是终端)。但是,printf()函数并不会立即将数据显示到终端上。相反,它会将数据写入到输出缓冲区中。输出缓冲区是一个临时存储区域,用于存放printf()函数打印的数据,直到满足一定条件时才将其刷新(即将数据发送到终端并显示出来)。

这些条件包括:

1. 遇到换行符 \nprintf()函数遇到换行符时,输出缓冲区会被自动刷新,将缓冲区中的数据输出到终端并显示出来。

2. 缓冲区满:当输出缓冲区满了,它也会被自动刷新。

3.调用fflush()函数:显式调用fflush(stdout)函数可以强制刷新输出缓冲区,将其中的数据输出到终端。

4. 程序结束:当程序正常终止时,所有的缓冲区都会被刷新。



3. 倒计时程序的编写


有了以上的知识储备,咱们就可以尝试编写一下简单的倒计时程序了,思路如下:

  • 首先新建一个time.c文件,然后再用我们之前讲的makefile工具来实现time.c文件的自动构建:

在这里插入图片描述

  • 编写time.c这个文件,实现思路:
  1. 假设我们倒数10s,到0s时结束,因此需要一个循环;
  2. 循环中,我们要实现每次出来一个数,都要对之前的数进行覆盖,所以要用到回车"\r";
  3. 由于printf()函数会会将输出的结果先输出到缓冲区,回车不会冲刷缓冲区,因此每次要用fflush(stdout)强制冲刷缓冲区;
  4. 每次循环秒数减1,并让程序休眠1s

🌝详细代码如下:

#include <stdio.h>
#include <unistd.h>
int main()
{
    int cnt = 10;

    while(cnt >= 0)
    {
    	// 打印的时候每次覆盖上一次出现的数字
        printf("倒计时:%2d\r",cnt);
        // 强制冲刷缓冲区
        fflush(stdout);
       --cnt;
        sleep(1);
    }
    printf("\n");
    return 0;
}

  • make命令进行编译:(⏳这边就可以动态运行了哈,感兴趣的可以自己试一下⌛)

在这里插入图片描述

  • 这里有个小拓展,如果我们要覆盖上次的数字是4位,这次是三次(比如1000到999),可以用%4d这个输出形式来解决,也可以用下面这种方法:
#include <stdio.h>
#include <unistd.h>
int main()
{
    int cnt = 1000;
    int tmp = cnt;
    int num = 0;
    while (tmp)
    {
        ++num;
        tmp /= 10;
    }
    while(cnt >= 0)
    {
    	// 主要就是这里的变化,用最大数字的位数来做占位符
        printf("倒计时:%*d\r",num, cnt);
        fflush(stdout);
       --cnt;
        sleep(1);
    }
    printf("\n");
    return 0;
}



4. 简易进度条的实现



好啦,有了以上的知识作为基础,咱们就可以进入正题啦!😎编写简易的进度条。😎


👨‍💻效果图展示

总共有三个部分:

1. 我们要实现的进度条用#来进行加载;

2. 后面要有数据来表示现在加载的进度是多少(百分数);

3. 最后用一个动态旋转的类来表示程序还在继续加载


在这里插入图片描述

👨‍💻实现思路


1. 动态加载的过程

动态加和之前的倒计时差不多,每次都要覆盖上次出现的#,具体思路如下:


1. 定义一个字符类型数组char *str,用memset()函数进行初始化(‘\0’);

2. 循环100次,每次循环都在数组中加一个#,并打印str('\r’进行覆盖);

3. 强制冲刷缓冲区;


2. 进度加载

我们可以用每次循环的次数来当作是当前加载的进度,当然还要进行覆盖,具体思路如下:


1. 每次循环都以当前的循环次数作为加载进度;

2. 每次覆盖上一次的进度;

3. 强制冲刷缓冲区。

4. 程序休眠(可以用usleep()函数,单位是微秒)


3. 动态旋转

定义一个数组,并初始化为-\\/-,覆盖的方法和之前类似,就不详细说了。


👨‍💻具体代码实现

#include "process_bar.h"
#include <memory.h>
#include <unistd.h>
#define style '#'
#define round "-\\/-"
void test()
{
    int i = 0;
    char str[100];
    memset(str,'\0',sizeof(str));
    while (i <= 100)
    {
        str[i] = style;
        printf("[%-100s][%d%%][%c]\r",str,i,round[i % 4]);
        fflush(stdout);
        ++i;
        usleep(10000);
    }
    printf("\n");
}

在这里插入图片描述



👨‍💻第二版本

我们正常用进度条肯定不是单独使用的,会结合其他的场景,例如下载界面,登陆界面


对于要下载的文件,肯定有文件大小,下载的时候网络也有它的带宽,所以在下载的时候,每次下载的大小都是一个带宽,我们可以先写一个下载的函数:

download函数:

void download()
{
   double bandwidth = 1024 * 1024 * 1.0;
   double filesize = 1024 * 1024 * 10.0;
   double cur = 0.0;
   while (cur <= filesize)
   {
   	   // 调用进度条函数
       test(filesize, cur);
       // 每次增加带宽
       cur += bandwidth;
       usleep(20000);
   }
   printf("\n");
   printf("this file has been downloaded\n");
}

进度条函数:

void test(double total, double current)
{
    char str[101];
    memset(str,'\0',sizeof(str));
    int i = 0;
    // 这次的比率
    double rate = (current * 100) / total;
    // 循环次数
    int loop_count = (int)rate;
    while (i <= loop_count)
    {
        str[i++] = style; 
    }
    printf("[%-100s][%.1lf%%][%c]\r",str,rate,round[loop_count % 4]);
    fflush(stdout);
}

回调函数版本(完整):

// 头文件 process_bar.h
#include <stdio.h>

typedef void(*callback_t)(double, double);// 函数指针(回调函数)

void test(double total, double current);

// 函数实现文件 process_bar.c
#include "process_bar.h"
#include <memory.h>
#include <unistd.h>
#define style '#'
#define round "-\\/-"

void test(double total, double current)
{
    char str[101];
    memset(str,'\0',sizeof(str));
    int i = 0;
    double rate = (current * 100) / total;
    int loop_count = (int)rate;
    while (i <= loop_count)
    {
        str[i++] = style; 
    }
    printf("[%-100s][%.1lf%%][%c]\r",str,rate,round[loop_count % 4]);
    fflush(stdout);
}

// main.c 主函数和 download 函数
#include "process_bar.h"
#include <unistd.h>

double bandwidth = 1024 * 1024 * 1.0;
void download(double filesize, callback_t cb)
{
   double cur = 0.0;
   while (cur <= filesize)
   {
       cb(filesize, cur);
       cur += bandwidth;
       usleep(20000);
   }
   printf("\n");
   printf("this file has been downloaded\n");
}

int main()
{
    download(1024*1024*100.0,test);
    download(1024*1024*20.0,test);
      
    return 0;
}

在这里插入图片描述

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

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

相关文章

coherence protocal基础

一致性整体抽象 coherence protocol是通过保证如下的两点invariants&#xff0c;来实现一致性的&#xff1b; SWMR invariant, 对于任何一个地址&#xff0c;任何时刻&#xff0c;都只会有一个core写&#xff0c;可能会有多个core读&#xff1b;Data-value invariant&#xf…

每天五分钟深度学习:数学中的极值

本文重点 在数学领域中,极值是一个极其重要的概念,它不仅在纯数学理论研究中占据核心地位,而且在工程、物理、经济等实际应用领域也发挥着不可替代的作用。极值问题涉及函数的最大值和最小值,是微积分学中的一个基本问题。本文旨在详细介绍数学中的极值概念、性质、求解方…

Python查询PostgreSQL数据库

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; Python与PostgreSQL的连接 需要了解如何在Python中连接到PostgreSQL数据库。这通常涉及到使用一个库&#xff0c;如psycopg2&#xff0c;它是Python中用于PostgreSQL的最流行的适配器。安装psycopg2非常简单&#x…

202466读书笔记|《一天一首古诗词》——借问梅花何处落,风吹一夜满关山

202466读书笔记|《一天一首古诗词》——借问梅花何处落&#xff0c;风吹一夜满关山 上册下册 《一天一首古诗词》作者李锡琴&#xff0c;蛮早前加入书架的已购买书籍&#xff0c;这次刚好有点时间&#xff0c;利用起来读完。 赏析没有细看&#xff0c;只读了诗词部分&#xff0…

Cocos creator实现《战机长空》关卡本地存储功能

Cocos creator实现《战机长空》关卡本地存储功能 Cocos creator在开放小游戏过程中&#xff0c;经常会出现设置关卡&#xff0c;这里记录一下关卡数据本地存储功能。 一、关卡设置数据 假如我们有关卡数据如下&#xff0c; let settings [ { level: 1, // 第1关 score: 0,…

uniapp的app端推送功能,不使用unipush

1&#xff1a;推送功能使用htmlPlus实现&#xff1a;地址HTML5 API Reference (html5plus.org) 效果图&#xff1a; 代码实现&#xff1a; <template><view class"content"><view class"text-area"><button click"createMsg&q…

Spring框架学习笔记(一):Spring基本介绍(包含IOC容器底层结构)

1 官方资料 1.1 官网 https://spring.io/ 1.2 进入 Spring5 下拉 projects, 进入 Spring Framework 进入 Spring5 的 github 1.3 在maven项目中导入依赖 <dependencies><!--加入spring开发的基本包--><dependency><groupId>org.springframework<…

SpringBoot集成微信支付V3版本流程(商户平台篇)

一、前言 微信支付账号类型分为商户平台和合作伙伴平台&#xff0c;今天主要是梳理商品平台微信支付流程。 商品平台文档地址&#xff0c;(在接入前建议仔细阅读这份文档&#xff0c;会少走很多弯路!!!) 小程序下单 - 小程序支付 | 微信支付商户文档中心 二、接入流程 以下…

qml 和 c++类的数据交互

1、 新建一个需要交互的C++类 1)添加QObject头文件 2)添加自QObject的继承 3)添加Q_OBJECT宏 4)使用Q_PROPERTY,定义两个交互的属性,并设置读写的方法和变更属性的信号。 5)添加方法、槽函数和变量 2、在main.cpp中添加实例化对象的QML上下文 1)添加需要QML交互的…

多个.C文件被编译为一个可执行文件的详细过程

多个.C文件被编译为一个可执行文件的详细过程 文章目录 多个.C文件被编译为一个可执行文件的详细过程前言一、一个.C文件的编译过程二、多个.C文件的链接过程1.文件信息2.链接过程3.makefile 总结 前言 C语言经典的 “hello world ” 程序从编写、编译到运行&#xff0c;看到屏…

html实现网页插入音频

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文主要介绍html中 如何插入音乐和视频 视频插入 标签:<video></video> 兼容格式:mp4,因为别的浏览器都有不兼容的格式&#xff0c;唯一对mp4全都兼容。所以尽量使用mp4格式。 属性: 属性属性值…

249 基于matlab的MED、OMEDA、MOMEDA、MCKD信号处理方法

基于matlab的MED、OMEDA、MOMEDA、MCKD信号处理方法。最小熵反褶积(MED)&#xff0c;最优最小熵反卷积调整卷积 (OMEDA),多点最优最小熵解卷积调整&#xff08;Multipoint Optimal Minimum Entropy Deconvolution Adjusted&#xff0c;MOMEDA&#xff09;&#xff0c;最大相关峭…

【Shell脚本】Shell编程之循环语句

目录 一.循环语句 1.for语句的结构 1.1.格式 1.2.实操案例 案例1. 案例2. 案例3. 案例4. 2.while语句的结构 2.1.格式 2.2.实操案例 案例1. 案例2. 案例3. 案例4. 3.until循环命令 3.1.格式 3.2.实操案例 案例1. 二.补充 1.常用转义符 一.循环语句 1.for…

JAVA 双亲委派之一

JAVA 双亲委派之一 JVM类加载流程 java语言系统内置了众多类加载器&#xff0c;从一定程度上讲&#xff0c;只存在两种不同的类加载器&#xff1a;一种是启动类加载器&#xff0c;此类加载由C实现&#xff0c;是JVM的一部分&#xff1b;另一种就是所有其他的类加载器&#xf…

IF:23.2|从实验室到田间,微生物干预提高植物抗逆

期刊&#xff1a;Nature Food 影响因子&#xff1a;23.2 发表时间&#xff1a;2023年10月 本研究介绍了一种名为SynCom的微生物组合&#xff0c;该组合Rhodococcus erythropolis和Pseudomonas aeruginosa两种微生物组成。这两种微生物能够帮助水稻抵抗铝毒害和磷缺乏&…

springboot3项目练习详细步骤(第二部分:文章分类模块)

新增文章分类 接口文档 业务实现 参数校验 文章分类列表 接口文档 业务实现 获取文章分类详情 接口文档 业务实现 更新文章分类 接口文档 业务实现 分组校验 问题 概念 实现步骤 总结 删除文章分类 接口文档 业务实现 该模块大部分请求的路径相同&…

mac安装禅道

前提已安装&#xff1a;phpapacheMySQL mac安装 php7.1/apache-CSDN博客 安装MySQL 一、禅道下载 安装官方文档 源码包下载地址&#xff1a;禅道下载 - 禅道开源项目管理软件 。 1. 解压禅道源码包 2. 将解压后的文件复制到Apache访问目录下 &#xff08;默认路径为 /Libra…

【进程替换】多进程程序替换原理 | 进程程序替换函数 | execlexecv | execlpexecvp

目录 多进程程序替换 多进程程序替换原理 进程程序替换函数详解 execl&execv execlp&execvp execle&execvpe execve 多进程程序替换 我们想要进程替换的同时不影响旧的进程&#xff08;使用多进程版&#xff09;fork创建子进程&#xff0c;让子进程去替换执…

Neuralink首个脑机接口患者:打游戏、搞研究两不误,重获自主能力

今年1月28日&#xff0c;Neuralink首次将侵入式脑机接口植入人类患者Noland Arbaugh的大脑。100天后&#xff0c;这家由埃隆马斯克创立的公司公布了最新的进展。从Neuralink的更新中我们可以看到&#xff0c;Arbaugh的恢复情况超出预期&#xff0c;他的用户体验也非常积极。 原…

回溯算法—组合问题

文章目录 介绍应用问题基本流程算法模版例题&#xff08;1&#xff09;组合&#xff08;2&#xff09;电话号码的字母组合 介绍 回溯算法实际上是 一个类似枚举的搜索尝试过程&#xff0c;主要是在搜索尝试过程中寻找问题的解&#xff0c;当发现已不满足求解条件时&#xff0c;…