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

 更多精彩内容.....

🎉❤️播主の主页✨😘

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.rhkb.cn/news/490828.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ubuntu24.04】PDFMathTranslate 本地PDF翻译GPU部署

https://huggingface.co/spaces/reycn/PDFMathTranslate-Docker排不上号官方都是要安装包,感觉可以本地试着源码部署一下, http://localhost:7860/官方是这个端口,但是我本地启动是:5000IDEA 里本地 backend启动效果 GUI 是监听7860的

基于卷积神经网络的垃圾分类系统实现(GUI应用)

1.摘要 本文主要实现了一个卷积神经网络模型进行垃圾图像分类&#xff0c;为了提高垃圾分类模型的准确率&#xff0c;使用使用Batch Normalization层、使用早期停止策略来防止过拟合等方法来优化模型&#xff0c;实验结果显示最终优化后的模型准确率较高90%左右。最终&#xf…

Vulnstack红日安全内网域渗透靶场2实战攻略

一&#xff1a;环境搭建 新增的网卡VMnet2&#xff0c;ip调成10段。 PC配置如下&#xff1a; DC在该环境中充当是域控。DC配置如下 &#xff1a; WEB配置&#xff1a;需要两块网卡&#xff0c;相当于网关服务器。 作者把外网网段都写成了192.168.111.1/24&#xff0c;我们可以…

Http协议在网站中的体现

文章目录 1. Http协议简介2. 网站中的体现2.1 访问网站2.2 请求2.3 请求头2.4 请求方式2.5 响应 3. 总结 1. Http协议简介 HTTP&#xff08;超文本传输协议&#xff09; 是一种广泛应用于互联网上的应用层协议&#xff0c;用于在Web浏览器和Web服务器之间传输数据。HTTP协议定…

JavaWeb——前端三剑客

前言&#xff1a;今天开始学习JavaWeb相关内容了&#xff0c;陆续会总结一些前后端分离开发的相关知识&#xff0c;有遗漏和错误的地方欢迎大家指出~ 目录 一、前端三剑客二、HTML2.1 HTML介绍2.2 常用标签 三、 CSS3.1 CSS介绍3.2 CSS引用的三种形式3.3. CSS选择器及其类型3.…

【经典】制造供应链四类策略(MTS、MTO、ATO、ETO)细说

关注作者 制造供应链的牛鞭问题与复杂问题主要是从两个方面解决&#xff0c;一是同步化供应链消减从需求到供应的放大效应&#xff0c;二是供应链细分&#xff0c;针对不同的客户、不同的需求供应的匹配策略来应对复杂性&#xff0c;更好的满足客户并以最低的总成本来实现。 对…

fixture装饰器

普通代码案例&#xff1a; python本身执行 import pytestdef init_new():print("init_new...")return Truedef test_case(init_new):if init_new is True:print("如果init_new返回True&#xff0c;就执行用例test_case")if __name__ __main__:#用python本…

数智读书笔记系列008 智人之上:从石器时代到AI时代的信息网络简史

书名:智人之上&#xff1a;从石器时代到AI时代的信息网络简史 作者:&#xff3b;以&#xff3d;尤瓦尔赫拉利 译者:林俊宏 出版时间:2024-09-01 ISBN:9787521768527 中信出版集团制作发行 作者信息 尤瓦尔・赫拉利 1976 年出生于以色列海法&#xff0c;是牛津大学历史学…

【C++】10___文件操作

目录 一、文本文件---写文件 二、文本文件---读文件 三、二进制文件---写文件 四、二进制文件---读文件 一、文本文件---写文件 通过文件操作可以将数据持久化 对文件操作需要包含头文件<fstream> 文件类型分两类&#xff1a; 文本文件&#xff1a;文件以文本的ASCII码形…

信号处理:概念、技术、领域

目录 基本概念 主要技术 应用领域 信号处理是一个涉及分析、修改和再生信号的多学科领域。信号可以是各种形式的&#xff0c;例如声音、图像、视频或其他类型的监测数据。信号处理的主要目标是提取有用的信息并增强信号的质量。以下是信号处理的一些基本概念和应用&#xff…

排序算法(5):归并排序

问题 排序 [30, 24, 5, 58, 18, 36, 12, 42, 39] 归并排序 归并排序采用分治法&#xff0c;将序列分成若干子序列&#xff0c;每个子序列有序后再合并成有序的完整序列。 在数组排序中&#xff0c;如果只有一个数&#xff0c;那么它本身就是有序的。如果有两个数&#xff0…

vue 自定义组件image 和 input

本章主要是介绍自定义的组件&#xff1a;WInput&#xff1a;这是一个验证码输入框&#xff0c;自动校验&#xff0c;输入完成回调等&#xff1b;WImage&#xff1a;这是一个图片展示组件&#xff0c;集成了缩放&#xff0c;移动等操作。 目录 一、安装 二、引入组件 三、使用…

基于Java的图书借阅管理系统详细设计和实现

目录 一、前言介绍&#xff1a; 二、主要技术&#xff1a; 2.1 Java技术介绍&#xff1a; 2.2 MYSQL数据库&#xff1a; 三、系统设计&#xff1a; 3.1 系统架构设计&#xff1a; 3.2 登录时序图设计&#xff1a; 四、功能截图&#xff1a; 4.1 用户登录注册 4.2 系统…

每天五分钟深度学习:解析m个样本向量化前向传播的原理

本文重点 上一节课程中,我们学会了多样本的前向传播的向量化形式,使用这种方式我们可以同时计算m个样本的前向传播,我们将m个样本以矩阵形式表示,实现了m个样本的向量化,本节课程我们再来看一下为什么使用上节课程的方式就可以完成m个样本的向量化。 x(1)、x(2)、x(3)在…

Android显示系统(10)- SurfaceFlinger内部结构

Android显示系统(01)- 架构分析 Android显示系统(02)- OpenGL ES - 概述 Android显示系统(03)- OpenGL ES - GLSurfaceView的使用 Android显示系统(04)- OpenGL ES - Shader绘制三角形 Android显示系统(05)- OpenGL ES - Shader绘制三角形(使用glsl文件) Android显…

软考高级架构 - 11.1- 信息物理系统CPS

信息物理系统CPS 信息物理系统(CPS)是控制系统、嵌入式系统的扩展与延伸。通过集成先进的感知、计算、通信、控制等信息技术和自动控制技&#xff0c;构建了物理空间与信息空间中人、机、物、环境、信息等要素相互映射、适时交互、高效协同的夏杂系统。 CPS的本质是基于…

数据可视化的Python实现

一、GDELT介绍 GDELT ( www.gdeltproject.org ) 每时每刻监控着每个国家的几乎每个角落的 100 多种语言的新闻媒体 -- 印刷的、广播的和web 形式的&#xff0c;识别人员、位置、组织、数量、主题、数据源、情绪、报价、图片和每秒都在推动全球社会的事件&#xff0c;GDELT 为全…

【GIS教程】使用GDAL-Python将tif转为COG并在ArcGIS Js前端加载-附完整代码

目录 一、数据格式 二、COG特点 三、使用GDAL生成COG格式的数据 四、使用ArcGIS Maps SDK for JavaScript加载COG格式数据 一、数据格式 COG&#xff08;Cloud optimized GeoTIFF&#xff09;是一种GeoTiff格式的数据。托管在 HTTP 文件服务器上&#xff0c;可以代替geose…

Git-分布式版本控制工具

目录 1. 概述 1. 1集中式版本控制工具 1.2分布式版本控制工具 2.Git 2.1 git 工作流程 1. 概述 在开发活动中&#xff0c;我们经常会遇到以下几个场景&#xff1a;备份、代码回滚、协同开发、追溯问题代码编写人和编写时间&#xff08;追责&#xff09;等。备份的话是为了…

【收藏】Cesium 限制相机倾斜角(pitch)滑动范围

1.效果 2.思路 在项目开发的时候&#xff0c;有一个需求是限制相机倾斜角&#xff0c;也就是鼠标中键调整视图俯角时&#xff0c;不能过大&#xff0c;一般 pitch 角度范围在 0 至 -90之间&#xff0c;-90刚好为正俯视。 在网上查阅了很多资料&#xff0c;发现并没有一个合适的…