【Linux】自定义项目-进度条

news2024/12/17 10:12:32

 更多精彩内容.....

🎉❤️播主の主页✨😘

Stark、-CSDN博客

准备工作:"\r"与"\n"字符

①:基本含义

在C语言和Linux环境中,\r是回车符,\n是换行符,用于控制文本格式和输出。在创建进度条小程序前我们应该理解这两个字符的含义。

\r(回车符):表示回到行首。在文本中,它会将光标移回当前行的开始,但不会换到下一行。

\n(换行符):表示换到下一行,他会将光标移动到下一行的开始位置。在Linux和Unix系统中,使用\n来表示行结束。

②:深入研究

下面我们将一步一步来使用这两个符号从而引导读者去理解其在进度条程序中的用法:

从上面我们可以看到,输出第一行的123456后,将\r输出我们的光标回到了行首,所以下一行的printf将9999输出时,覆盖掉了原来的1234,对此,我们就可以实现在一行之中不断更新新的内容的问题了,这不也正是进度条所必备的嘛。我们使用循环来做一遍:

按理来说我这里将会显示出最后的结果,但是并没有,为什么?其实不是没有显示,而是被前面的主机名给覆盖掉了,也就是所谓的【stark@ubuntu: ... $ 】 ,那我们只需要输出完毕之后,在程序的结束处加一个换行就可以了吧:

结果是显示出来了,但是有点快,(这里注释有个问题,usleep的参数的单位是微秒不是毫秒,所以我们这里其实是0.005秒), 调整时间 ,但是输出结果是一直处于无显示,直到最后才显示,这是为什么?

此时我猜测,并不只是覆盖那么简单,还有\r回退后会导致行走路径上显示的字符消失。那么我们先调换顺序,将打印回车符放到睡眠下面:再来观测结果,但结果依旧不对,并不是。

猜测的原因并不成立。那么我就猜测,延迟输出是因为每次输出并不是直接输出到屏幕上的,而是有一个中间过程在卡着这个操作,此时我们似乎想到了之前学习C语言时持续输入东西直至\n,从而遇到的问题,我们当时好像涉及到一个叫做缓冲区的词。那这里我们就大胆猜测,是不是先输出到缓存区,等到缓存区中的内容到达一个特定条件时才会输出到屏幕中?为了验证猜想,我们试着询问AI,得到了答案:

输出没有立即显示在屏幕上的问题通常是因为标准输出(stdout)是缓冲的。缓冲意味着输出数据首先被存储在内存中的一个缓冲区中,而不是立即发送到屏幕或其他输出设备。当缓冲区满了或者遇到特定的刷新条件时,缓冲区的内容才会被实际输出。

根据这段结果,我们可以尝试刷新缓冲区来让它马上输出:

经过这样的编码修改后,我们得到了想要的结果:一个一个的输出@。此时有人开始想了,那我不用\r,每次输出@,然后睡眠,下次继续输出一个@,这样既不需要内部循环,也能达到同样的效果。但是你要知道,进度条并不单单只是修改@的个数,而是有一个固定的进度条样式,然后不断地修改输出的内容,进度条的思想 与 在终端中设置一个自动计时的时钟一样,是修改输出内容,而非单纯的增加输出内容达到新的结果。

那么现在我们对\r和\n的使用应该明确了:前者与fflush(stdout)用于刷新输出结果,后者用于防止主机名覆盖输出结果。下面就开始实现进度条:

设计工作:进度条的设计

进度条是一个什么样子的呢?首先有一个待填充进度槽,有填充内容,有进度百分比显示,有加载动画。

Ⅰ、进度槽

进度槽我们可以使用[ ]来设计,中间给出待填充的空间。下面使用多行文本模拟出基本样式:

[          ]
[#         ]
[##        ]
[###       ]
[####      ]
[#####     ]
[######    ]
[#######   ]
[########  ]
[######### ]
[##########]

如果我们合并到一行来输出这些内容,那么我们就可以实现了。

Ⅱ、填充符 

有了槽这个容器,那么接下来我们就可以使用东西来填充这个容器了。我们可以使用任何你喜欢的符号来填充。那么我们该如何保证在填充时还能保持着进度槽这个容器的样式不改变:

对上述输出进行一下分析:

第一行:1个 [ ,0个#,10个空格,1个 ]

第二行:1个 [ ,1个#,9个空格,1个 ]

......规律非常的简单,我们来设计一套公式来输出上述内容:

for(int i=1;i<=10;i++){
    printf("[");
    for(int j=1;j<=10;j++){
        if(j<=i)printf("@");
        else printf(" ");
    }
    printf("]\r");
    fflush(stdout);
    usleep(500000);//睡眠0.5秒
}           
printf("\n");                                                                                                                                                       

取代上述我们的@那段代码中的for循环就行了。验证一下,与预期结果一致 。

Ⅲ、百分比

百分比就是当前的填充对槽总容器的占有率,也就是当前的i与总数10的比的百分比形式:

const int len=10;
for(int i=1;i<=len;i++){
    printf("[");
    for(int j=1;j<=len;j++){
        if(j<=i)printf("@");
        else printf(" ");
    }
    printf("]");
    printf("(%3d%%)\r", (int)(i*100/len) );
    fflush(stdout);
    usleep(50000);//睡眠0.05秒
}       
printf("\n");    

%3d代表右对齐三个字符,因为我们的预期百分比最多100三位数。

这里需要注意的是:%%代表的是一个%,不然%加上后面的特定内容代表占位符,会出现错误,所以两个%%就相当于\\,起到转义的作用。

 Ⅳ、加载动画

什么是加载动画呢?这里的加载动画其实就是为了模拟我们加载时一直在转圈圈的东西。那么我们知道Linux中大多东西都是用文字或者说字符来实现的,我们怎么整一个转圈圈的东西呢?答案是:转笔,一根笔,转一圈为一个圆,循环这个操作就是不断加载。对应到字符就是:【|  /  -  \】

不妨想一下,将这四个字符连起来,输出,是不是就是一个转笔。相信看过动漫的都知道,动漫是一帧一帧的图片构成的,连续播放就成为了动画。那么我们这四个字符就构成了一个圆所必需的四帧静态画面。那么我们就可以定义一个字符数组,分别存储这四个字符,需要注意的是\为转义字符,需要使用\\来代表一个 \ 字符。

然后循环使用这四个字符就是使用模运算的周期性来进行循环播放,对应代码为:

const int len=100;
const char fillchar='@';
const char gif[4]={'|','/','-','\\'};

for(int i=1;i<=len;i++){
    printf("[");
    for(int j=1;j<=len;j++){
        if(j<=i)printf("%c",fillchar);
        else printf(" ");
    }
    printf("](%3d%%)(%c)\r", (int)(i*100/len) , gif[i%4]);
    fflush(stdout);
    usleep(50000);//睡眠0.05秒
}   
printf("\n");   

Ⅴ、代码优化

优化:我们使用一个char数组来存储待填充字符,初始化为全空格字符,以空间换取内层for循环的时间。

const int len=100;
const char fillchar='@';
const char gif[4]={'|','/','-','\\'};

char buffer[len];
memset(buffer,' ',sizeof(buffer));//初始化为空格

for(int i=1;i<=len;i++){
    printf("[%s](%3d%%)(%c)\r",buffer,(int)(i*100/len) , gif[i%4]);
    fflush(stdout);
    usleep(50000);//睡眠0.05秒
    buffer[i-1]=fillchar;
}   
printf("\n");   

这样写,即提高了代码的可读性,又节省了时间。具体优化方法就是设置一个字符数组,长度为len,然后使用memset函数初始化该字符数组。打印时就可以使用占位符来整体输出结果,然后填充输出内容。经过刷新缓冲区及时输出结果,然后睡眠来让用户有时间看到输出的结果,最后在下次执行循环之前将第i-1个位置的字符设置为填充符fillchar;

运行结果:(看底行)


感谢大家!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenLinkSaas 2025年1月开发计划

先来看看OpenLinkSaas的大目标 在OpenLinkSaas的产品目标中&#xff0c;让开发人员更加方便的使用云资源是目标之一。通过各大云厂商的API&#xff0c;来可视化云上基础设施的数据是远远不够的。我们准备在2025年1月份增加方便管理和运营研发场景下服务器的能力。 这部分的功能…

电工电子技术实验:电压比较器及其应用电路

实验目的 1&#xff0e;了解电压比较器与运算放大器的性能区别&#xff1b; 2&#xff0e;掌握电压比较器的结构及特点&#xff1b; 3&#xff0e;掌握电压比较器电压传输特性的测试方法&#xff1b; 4&#xff0e;学习比较器在电路设计中的应用 实验原理 电压比较器是一…

代理 IP 行业现状与未来趋势分析

随着互联网的飞速发展&#xff0c;代理 IP 行业在近年来逐渐兴起并成为网络技术领域中一个备受关注的细分行业。它在数据采集、网络营销、隐私保护等多个方面发挥着重要作用&#xff0c;其行业现状与未来发展趋势值得深入探讨。 目前&#xff0c;代理 IP 行业呈现出以下几个显著…

旅游系统旅游小程序PHP+Uniapp

旅游门票预订系统&#xff0c;支持景点门票、导游产品便捷预订、美食打卡、景点分享、旅游笔记分享等综合系统 更新日志 V1.3.0 1、修复富文本标签 2、新增景点入驻【高级版本】3、新增门票核销【高级版】4、新增门票端口【高级版】

【日常笔记】Spring boot:编写 Content type = ‘text/plain‘ 接口

一、项目场景&#xff1a; 接口&#xff1a;Context-Type&#xff1a;text/plain 方式&#xff1a;POST 项目场景&#xff1a;硬件回调接口 二、实战 PostMapping(value "/xx/xxx", consumes "text/plain" ) 2.1、接口 /*** return String* time 202…

STM32F407+LAN8720A +LWIP +FreeRTOS UDP通讯

STM32F407+LAN8720A +LWIP +FreeRTOS ping通 上一篇实现了LWIP ping 通 本篇实现UDP通讯 实现如下功能: 串口1空闲中断+DMA接收,收到数据用UDP发送UDP接收,收到数据用串口1发送STM32CUBEIDE配置和代码 1. 配置UARAT1的空闲中断+DMA接收 UART1接收到数据,释放信号量,在任…

KeyFormer:使用注意力分数压缩KV缓存

Keyformer: KV Cache Reduction through Key Tokens Selection for Efficient Generative Inference 202403&#xff0c;发表在Mlsys Introduction 优化KV cache的策略&#xff0c;主要是集中在系统级别的优化上&#xff0c;比如FlashAttention、PagedAttention&#xff0c;它…

3.9 网际控制报文协议ICMP

欢迎大家订阅【计算机网络】学习专栏&#xff0c;开启你的计算机网络学习之旅&#xff01; 文章目录 前言1 ICMP报文的封装2 ICMP差错报告报文的类型3 不应发送ICMP差错报告报文的情况4 常用的ICMP询问报文类型5 ICMP的应用 前言 网际控制报文协议&#xff08;ICMP&#xff09…

东北大学《2024年839自动控制原理真题》 (完整版)

本文内容&#xff0c;全部选自自动化考研联盟的&#xff1a;《东北大学839自控考研资料》的真题篇。后续会持续更新更多学校&#xff0c;更多年份的真题&#xff0c;记得关注哦~ 目录 2024年真题 Part1&#xff1a;2024年完整版真题 2024年真题

百度智能云千帆AppBuilder升级,百度AI搜索组件上线,RAG支持无限容量向量存储!

百度智能云千帆 AppBuilder 发版升级&#xff01; 进一步降低开发门槛&#xff0c;落地大模型到应用的最后一公里。在千帆 AppBuilder 最新升级的 V1.1版本中&#xff0c;企业级 RAG 和 Agent 能力再度提升&#xff0c;同时组件生态与应用集成分发更加优化。 • 企业级 RAG&am…

就业相关(硕士)

一、嵌入式 1.机器人行业 1.1 大致情况 要做机器人行业&#xff0c;主要技术栈是运动控制、深度学习、强化学习、具身智能等&#xff0c;主要求职方向有运动控制算法工程师和机器人算法工程师等等。大致薪资在30w到50w不等&#xff0c;主要看方向&#xff08;双211&#xff…

Selenium操作指南

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 大家好&#xff0c;今天带大家一起系统的学习下模拟浏览器运行库Selenium&#xff0c;它是一个用于Web自动化测试及爬虫应用的重要工具。 Selenium测试直接运行在…

OpenCV相机标定与3D重建(11)用于在图像上绘制世界坐标系的三条轴函数drawFrameAxes()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 从姿态估计绘制世界/物体坐标系的轴。 cv::drawFrameAxes 是 OpenCV 库中的一个函数&#xff0c;用于在图像上绘制世界坐标系的三条轴&#xff0…

spring学习(XML中定义与配置bean(超详细)。IoC与DI入门spring案例)

目录 一、配置文件(XML)中定义与配置bean。 &#xff08;1&#xff09;bean的基础配置。&#xff08;id、class&#xff09; &#xff08;2&#xff09;bean的别名配置。 1、基本介绍。 2、demo测试。 3、NoSuchBeanDefinitionException&#xff01; &#xff08;3&#xff09;…

Docker容器编排与Docker Compose

1. Docker Compose介绍与基础概念 Docker Compose是一个用于定义和运行多容器Docker应用的工具。通过Compose&#xff0c;用户可以用YAML文件来定义多个容器的服务、网络、存储等配置&#xff0c;并通过一个命令来启动、停止和管理这些容器。它简化了多容器应用的管理&#xf…

鸿蒙项目云捐助第七讲鸿蒙App应用的首页推荐模块布局的实现

鸿蒙项目云捐助第七讲鸿蒙App应用的首页推荐模块布局的实现 最后设置首页的推荐模块&#xff0c;参考模板如下图所示。 一、首页热门推荐模块的实现 对于热门推荐模块&#xff0c;先有上面的小标题栏&#xff0c;这里的标题栏也有一个小图标&#xff0c;首先从“百度图库”中…

MySQL八股-MVCC入门

文章目录 当前读&#xff08;加锁&#xff09;快照读&#xff08;不加锁&#xff09;MVCC隐藏字段undo-log版本链A. 第一步B.第二步C. 第三步 readview MVCC原理分析RCA. 先来看第一次快照读具体的读取过程&#xff1a;B. 再来看第二次快照读具体的读取过程: RR隔离级别 当前读…

基于单片机的无绳跳绳设计

基于单片机设计了一款无绳跳绳&#xff0c;采用传感器代替了绳子的摆动&#xff0c;从而实现了模拟跳绳的功能。其研究的方法是&#xff1a;以单片机作为这次设计的核心&#xff0c;它的外围包含有传感器模块、按键模块、显示模块、语音播报模块及电源模块等。本设计采用STM32芯…

【图像处理】利用numpy实现直方图均衡、自适应直方图均衡、对比度受限自适应直方图均衡

直方图均衡化是一种在图像处理技术&#xff0c;通过调整图像的直方图来增强图像的对比度。 本博客不利用opencv库&#xff0c;仅利用numpy、matplotlib来实现直方图均衡、自适应直方图均衡、对比度受限自适应直方图均衡 直方图均衡 包括四个流程 计算图像RGB三通道的归一化直…

Azure Function流式返回

最近用azure function做了一个api和llm交互&#xff0c;需要流式返回。但是默认不支持流返回&#xff0c;搜索了一下。记录。 官方文档&#xff1a;https://techcommunity.microsoft.com/blog/azurecompute/azure-functions-support-for-http-streams-in-python-is-now-in-prev…