当前位置: 首页 > news >正文

【Linux系统】—— 简易进度条的实现

【Linux系统】—— 简易进度条的实现

  • 1 回车和换行
  • 2 缓冲区
  • 3 进度条的准备代码
  • 4 第一版进度条
  • 5 第二版进度条

1 回车和换行

  先问大家一个问题:回车换行是什么,或者说回车和换行是同一个概念吗?
  可能大家对回车换行有一定的误解,本文在这里讲解一下:

假设我们是在写小作文

  • 换行:将笔尖换到下一格,即移动到下一行。
  • 回车:将笔尖移动到本行的开头。
      
    在这里插入图片描述

  在计算机中,换行符为「\n」,回车符为 「\r」,我们往往用「\r\n」来整体表示回车换行。
  但之前写 C语言 时,我们只用「\n」也能同时达到回车和换行的效果,这是在语言层面上,将 \n 解析成 \r\n
  
  

2 缓冲区

  下面我们非常粗略的了解一下缓冲区的概念:

先来段测试代码

#include <stdio.h>
#include <unistd.h>int main()
{printf("Hello Linux!\n");sleep(3);return 0;
}

: sleep() 函数的头文件为:<unistd.h>
  

在这里插入图片描述

  一切正常
  我们将 printf 中的「\n」去掉试试

#include <stdio.h>
#include <unistd.h>int main()
{printf("Hello Linux!");sleep(3);return 0;
}

在这里插入图片描述

  结果好像和我们想的有点不太一样。

  解释上面原因前,先问大家一个问题:上述代码是先执行 printf还是先执行sleep
  按结果来看,应该是先执行 sleep,再执行printf
  但事实恰恰相反,是先执行的 printf。在初学C语言时,我们知道一个程序有几种控制流:循环、判断、顺序。我们对应的程序在执行时永远都是从前往后执行的
  
  当程序执行到 sleep 语句时,它一定是把 printf 执行完了。可显示器上并没有显示,那在休眠的 3 秒期间,字符串 “Hello Linux” 在哪呢?在缓冲区里!
  简单理解一下:在内存中有一块内存块叫缓冲区,先将字符串临时存放在缓冲区里。缓冲区向显示器输出是行刷新,也就是说它遇到 \n 自动将缓冲区的内容刷新出去;如果没遇到就一直在缓冲区中呆着,直到程序退出时再自动刷新缓冲区,我们才能看到打印出的字符串。

  如果想让不带 ‘/n’ 的字符串立即刷新,可以用 fflush 函数

#include <stdio.h>
#include <unistd.h>int main()
{printf("Hello Linux!");fflush(stdout);sleep(3);return 0;
}

在这里插入图片描述

  
  

3 进度条的准备代码

  我们先不急着写进度条,先写几段测试代码

  先来实现一个倒计时

int main()
{int i = 9;while(i >= 0){   printf("%d\n", i); --i;}   return 0;
}

在这里插入图片描述

  
  现在它是换行进行打印,但我们想让它在同一个位置打印。这时我们可以运用前面学习到的回车符 「\r」

int main()
{int i = 9;while(i >= 0){   printf("%d\r", i); --i;sleep(1);}   return 0;
}

在这里插入图片描述

  为什么它一直不显示呢?而且最后程序结束了,命令行覆盖了,什么都没有
  这是因为数据一直在缓冲区没有刷新出来,而最后程序运行结束刷新缓冲区了,因为回车符,命令行从头开始写将数据覆盖了。

  我们手动刷新缓冲区,并且为了不让命令行覆盖数据,我们单独进行换行

int main()
{int i = 9;while(i >= 0){   printf("%d\r", i); fflush(stdout);--i;sleep(1);}   printf("\n");return 0;
}

在这里插入图片描述

  现在,我们写的代码就可以进行倒计时了……了吗?

  还没有,如果我们改成从 10 开始倒计时会怎样

在这里插入图片描述

  又出问题了。

  讲个小知识点:显示
  当我们向显示器中输出 12345 这个数时,显示器上本质上是输出 12345 这个数字还是 ‘1’ ‘2’ ‘3’ ‘4’ ‘5’ 这 5 个字符呢?
  答案是后者显示器是字符设备,它只认字符
  这也解释了为什么我们 printf 要格式化输出。比如我们输出一个 int a,printf 内部将其由整数转成字符串,再用类似 putc 的接口一个一个字符输出到显示器上

  怎么解决上述问题呢?很简单,将输出的显示的位宽改为 2 即可

int main()
{int i = 10; while(i >= 0){   printf("%-2d\r", i); fflush(stdout);--i;sleep(1);}   printf("\n");return 0;
}

  

4 第一版进度条

  我们想写一个怎么样的进度条:
  一对 [ ] 括起100个空字符;每加载 1% 就有一个 ‘#’ 替换一空字符;并在后面显示下载进度和转圈圈表示软件一直在下载

在这里插入图片描述

  
  首先创建多文件

在这里插入图片描述

  

  再写 makefile(对 makefile 有困惑的小伙伴可移步【Linux系统】—— make/makefile)

在这里插入图片描述

  
  基本框架如下:

在这里插入图片描述

  
  process.c 代码如下

在这里插入图片描述

  如果大家觉得休眠 1 秒时间太长,这里给大家再介绍一个新的休眠函数:usleep
  usleep 函数的休眠时间是以微妙为单位的,头文件同样是<unistd.h>

  效果如下:

在这里插入图片描述

  现在我们还需要加上百分比旋转光标。旋转光标是用来告诉用户该程序一直在下载中。
  百分比的实现很简单,这里就不单独介绍了,需要注意的是打印 ‘%’,要输入 ‘%%’ 表示取其字面值
  
  我们简单介绍一下简易光标如何实现
  其实旋转光标很简单,只需要 '|' '/' '-' '\' 不断循环打印即可(因为 '\' 是特殊字符,我们输入 '\\' 表示取字面值)
  
  至此,我们就完成了第一版进度条,代码如下

#include "process.h"
#include <string.h>
#include <unistd.h>#define NUM 101
#define STYLE '#'void process_v1()
{char buffer[NUM];memset(buffer, 0, sizeof(buffer));const char* lable = "|/-\\";int len = strlen(lable);int cnt = 0;while(cnt <= 100){   printf("[%-100s][%2d%%][%c]\r", buffer, cnt, lable[cnt % len]);fflush(stdout);buffer[cnt] = STYLE;++cnt;usleep(100000);}   printf("\n");
}

效果展示:

在这里插入图片描述

  
  

5 第二版进度条

  第一版本的进度条看起来像模像样的,其实它根本无法使用

  因为第一版本的进度条和下载的软件是各跑各的,可能软件值下载了 1% 但我们的进度条已经跑完了,而真实的进度条是要反应真实下载进度的。

  一个进度条,一定要结合具体的场景,边下载边更新进度条。

  我们定义变量 total 来表示要下载的总大小;speed 为下载的速度,当然实际的下载速度是浮动的,但这里为方便我们将其固定下来;current 表示当前已下载量。当然,真正的下载是要从网络中获取数据的,这点我们还没学,就用休眠时间来替代

// main.c
#include "process.h"
#include <unistd.h>
#include <stdio.h>double total = 1024;
double speed = 1.0;void DownLoad()
{double current = 0;while(current < total){   //下载代码usleep(3000);//充当下载数据current += speed;}   printf("download %lfMB Done\n", current);
}int main()
{DownLoad();return 0;
}

  现在的情况是我们不知道他正在下载,因此我们需要引入进度条。
  我们重新定义一个 FlushProcess()函数,FlushProcess()函数 的作用是根据当前的下载进度来打印进度条

部分代码如下

void FlushProcess(double total, double current)
{char buffer[NUM];memset(buffer, 0, sizeof(buffer));const char* lable = "|/-\\";int len = strlen(lable);static int cnt = 0;//不需要自己循环,填充#int num = (int)(current * 100 / total);int i = 0;for(; i < num; i++){   buffer[i] = STYLE;}   double rate = current / total;cnt %= len;printf("[%-100s][%.lf%%][%c]\r", buffer, rate * 100, lable[cnt]);++cnt;fflush(stdout);
}void DownLoad()
{double current = 0;while(current <= total){   //调用FlushProcess函数不断打印进度条FlushProcess(total, current);//下载代码usleep(3000);//充当下载数据current += speed;}   printf("\ndownload %.2lfMB Done\n", current);
}int main()
{DownLoad();return 0;
}

效果演示

在这里插入图片描述

  
  但是上述代码还有一点小问题:现在是下载需要进度条,如果以后是上传呢?上传也需要有对应的进度条。但此时的进度条函数 FlushProcess() 是硬加载在下载函数 DownLoad() 中的;如果是上传,需要的函数是 UpLoad(),那是不是在 UpLoad()函数中也要加载一份进度条 FlushProcess() 函数呢?这样做是不是太麻烦了?

  为了解决这个问题,我们可以使用函数指针

完整代码:

//process.h
#pragma one
#include <stdio.h>void FlushProcess(double total, double current);//process.c
#include "process.h"
#include <string.h>
#include <unistd.h>#define NUM 101
#define STYLE '#'void FlushProcess(double total, double current)
{char buffer[NUM];memset(buffer, 0, sizeof(buffer));const char* lable = "|/-\\";int len = strlen(lable);static int cnt = 0;//不需要自己循环,填充#int num = (int)(current * 100 / total);int i = 0;for(; i < num; i++){   buffer[i] = STYLE;}   double rate = current / total;cnt %= len;printf("[%-100s][%.lf%%][%c]\r", buffer, rate * 100, lable[cnt]);++cnt;fflush(stdout);
}//main.c
include "process.h"
#include <unistd.h>
#include <stdio.h>typedef void(*callback_t)(double total, double current);double total = 1024;
double speed = 1.0;void DownLoad(callback_t cb) 
{double current = 0;while(current <= total){   cb(total, current);//下载代码usleep(3000);//充当下载数据current += speed;}   printf("\ndownload %.2lfMB Done\n", current);
}int main()
{DownLoad(FlushProcess);return 0;
}

  
  
  
  


  好啦,本期关于 进度条 的知识就介绍到这里啦,希望本期博客能对你有所帮助。同时,如果有错误的地方请多多指正,让我们在 Linux 的学习路上一起进步!

相关文章:

【Linux系统】—— 简易进度条的实现

【Linux系统】—— 简易进度条的实现 1 回车和换行2 缓冲区3 进度条的准备代码4 第一版进度条5 第二版进度条 1 回车和换行 先问大家一个问题&#xff1a;回车换行是什么&#xff0c;或者说回车和换行是同一个概念吗&#xff1f;   可能大家对回车换行有一定的误解&#xff0…...

Qt 中使用 SQLite 数据库的完整指南

SQLite 是一款轻量级、嵌入式的关系型数据库&#xff0c;无需独立的服务器进程&#xff0c;数据以文件形式存储&#xff0c;非常适合桌面和移动端应用的本地数据管理。Qt 通过 Qt SQL 模块提供了对 SQLite 的原生支持&#xff0c;开发者可以轻松实现数据库的增删改查、事务处理…...

数智化时代的工单管理:从流程驱动到数据驱动-亿发

在数智化时代&#xff0c;工单管理系统已从简单的任务分发工具演变为企业运营的智能中枢。传统工单系统关注流程的线性推进&#xff0c;而现代工单管理系统则强调数据的全生命周期管理&#xff0c;通过智能算法实现工单的自动分配、优先级判定和效能优化。这种转变不仅提升了运…...

Large Language Model Distilling Medication Recommendation Model

摘要&#xff1a;药物推荐是智能医疗系统的一个重要方面&#xff0c;因为它涉及根据患者的特定健康需求开具最合适的药物。不幸的是&#xff0c;目前使用的许多复杂模型往往忽视医疗数据的细微语义&#xff0c;而仅仅严重依赖于标识信息。此外&#xff0c;这些模型在处理首次就…...

floodfill算法系列一>被围绕的区域

目录 整体思想&#xff1a;代码设计&#xff1a;代码呈现&#xff1a; 整体思想&#xff1a; 代码设计&#xff1a; 代码呈现&#xff1a; class Solution {int m,n;int[] dx {0,0,-1,1};int[] dy {-1,1,0,0};public void solve(char[][] board) {m board.length;n board[…...

Redis 01 02章——入门概述与安装配置

一、入门概述 &#xff08;1&#xff09;是什么 Redis&#xff1a;REmote Dictionary Server&#xff08;远程字典服务器&#xff09;官网解释&#xff1a;Remote Dictionary Server(远程字典服务)是完全开源的&#xff0c;使用ANSIC语言编写遵守BSD协议&#xff0c;是一个高…...

windows基于cpu安装pytorch运行faster-whisper-large-v3实现语音转文字

1.创建虚拟环境 conda create -n faster-whisper python3.10 conda activate faster-whisper 2.安装cpu版本的pytorch pip3 install torch torchvision torchaudio -i https://pypi.tuna.tsinghua.edu.cn/simple 3.验证pytorch安装结果 (faster-whisper) H:\big-model\faste…...

AI大模型(如GPT、BERT等)可以通过自然语言处理(NLP)和机器学习技术,显著提升测试效率

在软件测试中,AI大模型(如GPT、BERT等)可以通过自然语言处理(NLP)和机器学习技术,显著提升测试效率。以下是几个具体的应用场景及对应的代码实现示例: 1. 自动生成测试用例 AI大模型可以根据需求文档或用户故事自动生成测试用例。 代码示例(使用 OpenAI GPT API): …...

【Prometheus】prometheus黑盒监控balckbox全面解析与应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…...

CSS实现单行、多行文本溢出显示省略号(…)

在网页设计中&#xff0c;我们常常遇到这样的情况&#xff1a;文本内容太长&#xff0c;无法完全显示在一个固定的区域内。为了让界面看起来更整洁&#xff0c;我们可以使用省略号&#xff08;…&#xff09;来表示内容溢出。这不仅能提升用户体验&#xff0c;还能避免内容溢出…...

服务器中部署大模型DeepSeek-R1 | 本地部署DeepSeek-R1大模型 | deepseek-r1部署详细教程

0. 部署前的准备 首先我们需要足够算力的机器&#xff0c;这里我在vultr中租了有一张A16显卡一共16GB显存的服务器作为演示。部署的模型参数为14b的。如果需要部署满血版本671b的&#xff0c;需要更大的算力支持&#xff0c;这里由于是个人资金有限&#xff0c;就演示14b的部署…...

元学习之孪生网络Siamese Network

简介&#xff1a;元学习是一种思想&#xff0c;一般以神经网络作为特征嵌入的工具&#xff0c;实现对数据特征的提取&#xff0c;然后通过构造某种指标以引导优化器对模型参数进行优化。而最小化距离是最常见的学习目标&#xff0c;这就是熟知的度量学习&#xff0c;度量学习里…...

深入HBase——引入

引入 前面我们通过深入HDFS到深入MapReduce &#xff0c;从设计和落地&#xff0c;去深入了解了大数据最底层的基石——存储与计算是如何实现的。 这个专栏则开始来看大数据的三驾马车中最后一个。 通过前面我们对于GFS和MapReduce论文实现的了解&#xff0c;我们知道GFS在数…...

Python创建FastApi项目模板

1. 项目结构规范 myproject/ ├── app/ │ ├── core/ # 核心配置 │ │ ├── config.py # 环境配置 │ │ └── security.py # 安全配置 │ ├── routers/ # 路由模块 │ │ └── users.py # 用户路由 │ ├…...

TCNE 网络安全

一.概况 CTF&#xff08;Capture The Flag&#xff09;在网络安全领域中指的是网络技术人员之间进行技术竞技的一种比赛形式&#xff0c;它起源于1996年的DEFCON全球黑客大会&#xff0c;以代替之前黑客们通过互相发起真实攻击进行技术比拼的方式&#xff0c;现已成为全球范围网…...

车规MCU处理器选择Cortex-M7还是Cortex-R52?

车规mcu处理器选择Cortex-M7还是Cortex-R52&#xff1f;跟随小编从具体应用场景、安全等级&#xff08;ASIL&#xff09;、性能、成本进行分析吧。 01安全等级需求 ASIL-D&#xff08;如刹车、转向&#xff09;→ 必选R52。R52原生支持ASIL-D&#xff0c;硬件级错误检测&#…...

什么是计算机中的 “终端”?

在我们初学编程的时候&#xff0c;会遇到一个很重要的概念 ——终端。那它到底是什么呢&#xff1f; 在计算机领域&#xff0c;终端就像是我们和计算机进行对话的 “窗口”。我们可以在这个窗口里&#xff0c;用一些特定的命令来告诉计算机该做什么。比如&#xff0c;让计算机…...

LeetCode刷题---字符串---819

最常见的单词 819. 最常见的单词 - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 给你一个字符串 paragraph 和一个表示禁用词的字符串数组 banned &#xff0c;返回出现频率最高的非禁用词。题目数据 保证 至少存在一个非禁用词&#xff0c;且答案 唯一 。 par…...

SSH IBM AIX服务器相关指标解读

&#xff08;一&#xff09;ZPU使用率 含义 在IBM AIX服务器中&#xff0c;ZPU使用率反映了特定处理单元&#xff08;ZPU&#xff0c;假设是某种自定义或特定环境下的处理单元&#xff09;的资源利用程度。它表示ZPU在一段时间内处于忙碌状态执行任务的时间比例。例如&#xff…...

Wireshark TS | 再谈虚假的 TCP Spurious Retransmission

前言 在之前的《虚假的 TCP Spurious Retransmission》文章中曾提到一个错误判断为 TCP Spurious Retransmission&#xff0c;实际为 TCP Out-Of-Order 的案例&#xff0c;本次继续探讨一个虚假的 TCP Spurious Retransmission 案例。 问题背景 TCP Spurious Retransmission…...

超导量子比特与腔体共振控制技术解析

1. 超导量子比特与腔体共振控制协议概述 在超导量子计算领域&#xff0c;实现量子比特与谐振腔之间的高效耦合控制是构建可扩展量子处理器的关键技术。Jaynes-Cummings模型作为描述量子比特与谐振腔相互作用的基础理论框架&#xff0c;为理解这种耦合提供了清晰的物理图像。当量…...

ClaudeSync:连接本地与云端AI项目的自动化同步工具

1. 项目概述&#xff1a;ClaudeSync&#xff0c;一个连接本地与云端AI项目的桥梁 如果你和我一样&#xff0c;日常开发中重度依赖像Claude.ai这样的AI助手来辅助代码审查、架构设计甚至直接生成代码片段&#xff0c;那你一定遇到过这样的痛点&#xff1a;在本地IDE里改完代码&…...

构建开源审计知识库:从数据分析到协作实战

1. 项目概述&#xff1a;一个面向中文用户的审计技能知识库最近在GitHub上看到一个挺有意思的项目&#xff0c;叫youki992/zh-audit-skills-hub。光看这个名字&#xff0c;就能猜个八九不离十&#xff1a;这是一个专注于审计领域&#xff0c;并且是用中文构建的技能知识库。对于…...

基于向量化与语义匹配的职业路径推荐系统设计与实现

1. 项目概述&#xff1a;一个基于数据的职业路径推荐引擎最近在GitHub上看到一个挺有意思的项目&#xff0c;叫“career-recommender”。光看名字&#xff0c;你可能会觉得这又是一个老生常谈的“职业测评”工具&#xff0c;无非是让你做几道选择题&#xff0c;然后告诉你适合当…...

CodeFire:为AI编程助手构建持久记忆层,实现连续协作开发

1. 项目概述&#xff1a;为AI编程助手构建持久记忆层 如果你和我一样&#xff0c;深度依赖Claude Code、Gemini CLI这类AI编程助手来辅助日常开发&#xff0c;那你一定遇到过这个让人头疼的问题&#xff1a;每次开启一个新的会话&#xff0c;AI助手就像得了“健忘症”&#xf…...

TVA重塑智慧城市安防新范式(9)

重磅预告&#xff1a;本专栏将独家连载新书《AI视觉技术&#xff1a;从入门到进阶》精华内容。本书是《AI视觉技术&#xff1a;从进阶到专家》的权威前导篇&#xff0c;特邀美国 TypeOne 公司首席科学家、斯坦福大学博士 Bohan 担任技术顾问。Bohan先生师从美国三院院士、“AI教…...

B站视频转文字:3步搞定,让知识不再“一闪而过“

B站视频转文字&#xff1a;3步搞定&#xff0c;让知识不再"一闪而过" 【免费下载链接】bili2text Bilibili视频转文字&#xff0c;一步到位&#xff0c;输入链接即可使用 项目地址: https://gitcode.com/gh_mirrors/bi/bili2text 你是否曾为了一段精彩的B站课…...

基于RAG的代码库智能问答系统:从原理到实战部署

1. 项目概述&#xff1a;当GitHub仓库成为你的私人AI助手最近在折腾AI应用开发的朋友&#xff0c;可能都遇到过这样的场景&#xff1a;手头有一个不错的开源项目&#xff0c;想基于它做二次开发&#xff0c;或者想快速理解一个复杂项目的代码结构。传统的做法是&#xff0c;把整…...

中国技术出海的机遇与挑战:产品、合规与文化——软件测试视角的深度解析

当“中国制造”的标签逐渐被“中国智造”和“中国创造”所取代&#xff0c;技术出海已不再是头部企业的专属游戏&#xff0c;而成为整个科技产业的时代必答题。在这场宏大的叙事中&#xff0c;软件测试从业者常常被置于幕后&#xff0c;但事实上&#xff0c;产品质量的稳定性、…...

基于Claude AI的ASO自动化审计:架构、实现与工程实践

1. 项目概述与核心价值最近在AI应用开发圈子里&#xff0c;一个名为“claude-aso-audit-skill”的项目引起了我的注意。这个项目标题直译过来是“Claude ASO审计技能”&#xff0c;乍一看可能有点抽象&#xff0c;但作为一名在移动应用增长和AI工具化领域摸爬滚打了十多年的从业…...