【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;此思想称为控制反转。通俗的讲就…

前端面经-总结篇 http

下面是我在过去12天内&#xff0c;学习关于http的前端面经汇总。现在只是一些很基础的知识&#xff0c;后续还会补充&#xff0c;算是对之前学习的一个总结。 前端面经整理-CSDN博客 我主要参考的题目来源在这里。 本地存储 localstorage&#xff08;本地存储&#xff09;和…

功能篇:SpringBoot 实现静态、动态定时任务,本地动态定时任务调度

在Spring Boot中实现静态和动态定时任务可以通过使用Scheduled注解来配置静态的调度任务&#xff0c;以及通过编程方式创建动态的调度任务。下面我将分别介绍这两种方式。 ### 静态定时任务 对于静态定时任务&#xff0c;你可以直接在方法上使用Scheduled注解&#xff0c;并指定…

服务器ubuntu重装系统后将原来的用户进行关联

服务器ubuntu重装系统后将原来的用户数据进行关联 关联用户到已存在目录 sudo useradd user_name -m -s /bin/bash -d /home***/name添加sudo权限 vim /etc/sudoers# 文件末尾添加 user_name ALL(ALL:ALL) ALL更改拥有者 sudo chown -R user_name:user_name /home***/na…

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

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

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

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

docker mysql挂载

在提供的 docker run 命令中&#xff0c;已经挂载了三个卷到 MySQL 容器中&#xff1a;日志目录、数据目录和配置目录。然而&#xff0c;还没有挂载一个包含 cube_admin.sql 文件的目录。要将 SQL 文件放入容器中并在 MySQL 中执行它&#xff0c;可以按照以下步骤操作&#xff…

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

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

【蓝凌表单】JSP组件常用语法整理

JSP组件常用语法整理 必填非必填写法//必填 $("[name=extendDataFormInfo.value(fd_344677482769e2)]").attr("validate","requiredvalue"); //非必填 $(

Redis 数据备份与恢复

Redis 数据备份与恢复 1. 引言 Redis 作为一款高性能的键值数据库,被广泛应用于各种场景,如缓存、消息队列等。由于其重要性,对 Redis 数据进行定期备份是保证数据安全的关键措施。本文将详细介绍 Redis 数据的备份与恢复方法,确保在数据丢失或系统故障时能够迅速恢复。 …

音视频入门基础:MPEG2-TS专题(17)——FFmpeg源码中,解析TS program map section的实现

一、引言 由《音视频入门基础&#xff1a;MPEG2-TS专题&#xff08;16&#xff09;——PMT简介》可以知道&#xff0c;PMT表&#xff08;Program map table&#xff09;由一个或多个段&#xff08;Transport stream program map section&#xff0c;简称TS program map sectio…

华为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…