【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.mzph.cn/bicheng/64257.shtml

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

相关文章

Linux从0到1——初识线程【什么是线程/线程控制/详解tid】

Linux从0到1——初识线程 1. 什么是线程&#xff1f;1.1 线程的概念1.2 结合代码理解线程1.3 重谈地址空间1.4 线程的优缺点 2. 线程异常和线程用途3. Linux进程VS线程4. 详解pthread_create的arg参数4.1 给线程传参4.2 一次创建多个线程 5. 线程控制5.1 线程退出5.2 线程分离5…

[免费]SpringBoot+Vue校园社团管理系统(优质版)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue校园社团管理系统(优质版)&#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue校园社团管理系统(优质版) Java毕业设计_哔哩哔哩_bilibili 项目介绍 随着信息技术的迅速发展&#x…

114 二叉树展开为链表

解题思路&#xff1a; \qquad 题目中已经明确&#xff0c;要用先序遍历的顺序展开&#xff0c;那么就需要按照“中-左-右”的顺序遍历二叉树&#xff0c;剩下的问题在于如何在遍历过程中完成链表指针的更新。 \qquad 由于“右子节点”需要链接到左子树最后一个节点之后&#…

Kylin麒麟操作系统 | Nginx服务部署

目录 一、理论储备1. Nginx概述2. Nginx与Apache的区别3. Nginx的服务配置 二、任务实施任务1 Nginx的编译安装1. Server配置2. 客户端测试 任务2 Nginx反向代理1. Server1配置2. Server2配置3. 客户端测试 一、理论储备 1. Nginx概述 Nginx是一个轻量级的web服务器&#xff…

类OCSP靶场-Kioptrix系列-Kioptrix Level 1

一、前情提要 二、实战打靶 1. 信息收集 1.1. 主机发现 1.2. 端口扫描 1.3 目录爆破 1.4. 敏感信息 2.根据服务搜索漏洞 2.1. 搜索exp 2.2. 编译exp 2.3. 查看exp使用方法&#xff0c;并利用 3. 提权 二、第二种方法 一、前情提要 Kioptrix Level是免费靶场&#x…

Golang囊地鼠gopher

开发知识点-golang 介绍红队专题-Golang工具Fscan简介主要功能ubuntu 安装windows 安装常用命令:项目框架源文件common目录Plugins目录Webscan目录入口点插件扫描类型爆破插件common.ScantypeWebtitle函数webpoc扫描POC 执行CEL-GO 实践CEL指纹识别免杀源码特征参考链接红队专…

快速上手Spring注解、SpringAop

1 Spring 注解的使用 1 IOC 的概念 IOC&#xff08;Inversion of Control&#xff09;&#xff1a;控制反转。 使用对象时&#xff0c;由主动new产生对象转换为由外部提供对象&#xff0c;此过程中对象创建控制权由程序转移到外部&#xff0c;此思想称为控制反转。通俗的讲就…

数据地图怎么做?推荐这款数据可视化地图生成器

在数字化与信息化高速发展的今天&#xff0c;企业迎来了前所未有的发展机遇&#xff0c;规模迅速扩张&#xff0c;市场版图不断延伸。然而&#xff0c;伴随着这种快速的发展&#xff0c;一个不容忽视的问题逐渐浮出水面——如何精准高效地掌握分布在各地的分公司、业务点乃至整…

鸿蒙项目云捐助第九讲鸿蒙App应用的捐助详情页功能实现

鸿蒙项目云捐助第九讲鸿蒙App应用的捐助详情页功能实现 这里接下来继续实现捐助详情页的布局页面&#xff0c;也就是当用户进入到分类页面后&#xff0c;点击分类的每一个商品就进入到捐助商品的详情页&#xff0c;这里的布局可以从下面的模板演化而来。 下面根据这个模板来进…

【数学】矩阵的逆与伪逆 EEGLAB

文章目录 前言matlab代码作用EEGLAB 中的代码总结参考文献 前言 在 EEGLAB 的使用中&#xff0c;运行程序时出现了矩阵接近奇异值&#xff0c;或者缩放错误。结果可能不准确。RCOND 1.873732e-20 的 bug&#xff0c;调查 EEGLAB 后发现是 raw 数据的问题。 matlab代码 A_1 …

华为HarmonyOS NEXT 原生应用开发:鸿蒙中组件的组件状态管理、组件通信 组件状态管理小案例(好友录)!

文章目录 组件状态管理一、State装饰器1. State装饰器的特点2. State装饰器的使用 二、Prop装饰器&#xff08;父子单向通信&#xff09;1. Prop装饰器的特点2. Prop装饰器的使用示例 三、Link装饰器&#xff08;父子双向通信&#xff09;1. Link装饰器的特点3. Link使用示例 四…

Pytorch | 对比Pytorch中的十种优化器:基于CIFAR10上的ResNet分类器

Pytorch | 对比Pytorch中的十种优化器&#xff1a;基于CIFAR10上的ResNet分类器 CIFAR10数据集ResNet提出背景网络结构特点工作原理优势 代码实现分析utils.pymain.py导入必要的库设备选择与数据预处理定义加载训练集和测试集主函数部分训练部分测试部分 结果10种优化器对应的训…

Linux系统操作03|chmod、vim

上文&#xff1a; Linux系统操作02|基本命令-CSDN博客 目录 六、chmod&#xff1a;给文件设置权限 1、字母法 2、数字法&#xff08;用的最多&#xff09; 七、vim&#xff1a;代码编写和文本编辑 1、启动和退出 1️⃣启动 2️⃣退出 2、vim基本操作 六、chmod&#x…

徐州数字孪生工业互联网可视化技术,赋能新型工业化智能制造工厂

#徐州数字孪生工业互联网#在当下智能制造的热潮之下&#xff0c;徐州作为中国制造业的重要基地&#xff0c;正积极拥抱数字化转型&#xff0c;通过数字孪生工业互联网可视化技术&#xff0c;赋能新型工业化智能制造工厂&#xff0c;引领制造业向更高效、更智能、更绿色的方向发…

C# 探险之旅:第二十四节 - 类型class基础,一场“类”似的奇妙冒险

嘿&#xff0c;勇敢的探险家们&#xff01;欢迎来到C#王国的“类”似奇妙冒险&#xff01;今天&#xff0c;我们要深入探索一个神秘而强大的领域——class&#xff08;类&#xff09;。想象一下&#xff0c;class就像C#世界里的一块魔法土地&#xff0c;每块土地上都能孕育出独…

(五)机器学习 - 数据分布

数据分布&#xff08;Data Distribution&#xff09;是指数据在不同值或值区间内的分布情况&#xff0c;它描述了数据点在整个数据集中是如何分散或集中的。数据分布可以通过多种方式来分析和表示&#xff0c;包括图形和数值方法。 常见的数据分布特征和描述数据分布的方法&…

基于stm32的红外测温系统设计(论文+源码)

1总体方案设计 本课题为基于STM32的红外测温系统设计&#xff0c;在此将系统架构设计如图3.1所示&#xff0c; 整个系统包括STM32F103单片机&#xff0c;红外测温模块MLX90614&#xff0c;显示模块OLED12864&#xff0c;蜂鸣器以及按键等构成&#xff0c;在功能上&#xff0c;…

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

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

JSSIP的使用及问题(webRTC,WebSockets)

简介 项目中有一个需要拨打电话的功能&#xff0c;要求实时的进行音频接听&#xff0c;并且可以在电话接听或者挂断等情况下做出相应的操作。jssip作为一个强大的实现实时通信的javascript库&#xff0c;这不门当户对了嘛。 jssip&#xff08;官网&#xff1a; JsSIP - the J…

DP3复现代码运行逻辑全流程(六)—— gen_demonstration_adroit.sh 演示生成与可视化

用于生成演示、培训和评估的脚本都在 Scripts/ 文件夹中 DP3 通过 gen_demonstration 生成演示&#xff0c;即训练数据&#xff0c;例如: bash scripts/gen_demonstration_adroit.sh hammer 这将在 Adroit 环境中生成锤子任务的演示。数据将自动保存在 3D-Diffusion-Policy/…