Linux 实战:从零实现动态进度条(含缓冲区原理与多版本优化)

Linux 实战:从零实现动态进度条(含缓冲区原理与多版本优化)
在这里插入图片描述

🔥草莓熊Lotso:个人主页
❄️个人专栏: 《C++知识分享》《Linux 入门到实践:零基础也能懂》
✨生活是默默的坚持,毅力是永久的享受!


🎬 博主简介:

在这里插入图片描述

文章目录


前言:

Linux 开发中,进度条是最基础也最实用的系统程序之一 —— 无论是文件下载、编译构建还是数据处理,一个直观的动态进度条能极大提升用户体验。但看似简单的进度条,背后藏着行缓冲区、回车换行区别、字符刷新等关键知识点。本文从基础概念入手,先拆解进度条的实现逻辑,再逐步实现 “固定速度” 和 “自适应进度” 两个版本,最后优化细节让进度条更流畅美观,帮你不仅 “会写”,还能 “理解为什么这么写”。

一. 核心预备知识:掌握三大关键点,轻松避开进度条开发常见误区

在动手写代码前,必须先理清 3 个关键概念,否则容易出现 “进度条不刷新”“换行错乱” 等问题。

1.1 回车(\r)与换行(\n)的本质区别解析

  • 换行(\n:光标移动到下一行的行首,但不会回到当前行开头;我们日常使用它的时候其实是回车+换行的作用(=/r/n)
  • 回车(\r:光标回到当前行的行首,但不会移动到下一行;
  • 进度条的核心是 “在同一行反复覆盖刷新”,因此必须用\r让光标回到行首,再重新打印新的进度信息。

1.2 深入理解行缓冲区运行机制

C 语言的printf函数默认是 “行缓冲”— 只有遇到\n、缓冲区满或手动刷新(fflush(stdout))时,才会把缓冲区的内容输出到终端。

错误示例

#include<stdio.h>intmain(){printf("hello Lotso!");sleep(3);return0;}
  • 如果只写printf 而不加\n或fflush,内容会一直存在缓冲区,终端看不到任何输出,这就是很多人写进度条 “没反应” 的原因。

注意:虽然没显示出来,但是我们的C语言默认是顺序结构的,一定是先执行printf再执行sleep的。

示例修正

#include<stdio.h>intmain(){printf("hello bite!");fflush(stdout);sleep(3);return0;}

练手倒计时小程序:

#include<stdio.h>#include<unistd.h>intmain(){int cnt =10;for(;cnt >=0;cnt--){printf("倒计时: %-2d\r",cnt);// 注意格式控制fflush(stdout);sleep(1);}printf("\n");return0;}

1.3 进度条的核心构成元素详解

一个完整的动态进度条通常包含 3 部分:

  • 进度条主体: 用=等字符填充,直观显示完成比例;
  • 百分比: 显示完成进度(0%~100%);
  • 动态光标:|/-\循环切换,提示程序正在运行。
  • 附加信息: 如当前进度 / 总进度、传输速度,提升实用性。
在这里插入图片描述

二. 实战开发:打造动态彩色进度条

基于基础框架,我们会慢慢优化实现出 “彩色区分 + 速度显示 + 多场景适配” 的进度条,核心分为头文件、实现文件、主函数三部分。

2.1 基础版进度条模拟实现(演示原理,实际应用较少)

这个版本的其他文件我就不写了,就展示一个proces.c

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

2.2 自动化构建流程:Makefile编写详解

为了方便编译和清理,编写 Makefile 实现自动化构建,只需一条命令即可生成可执行文件:我们在之前讲过 Makefile 的编写策略,这里就不多说了直接展示

Bin=process_bar Cc=gcc Src=$(wildcard *.c)Obj=$(Src:.c=.o)$(Bin):$(Obj) @echo "$^ link to $@" @$(Cc)-o$@ $^ %.o:%.c @echo "compiling $< to $@" @$(Cc)-c $< .PHONY:clean clean: @echo "File cleanup complete" @rm -f$(Obj)$(Bin) .PHONY:debug debug: @echo "Bin: $(Bin)" @echo "Cc: $(Cc)" @echo "Src: $(Src)" @echo "Obj: $(Obj)"

2.3 头文件设计(process.h):接口函数声明

定义进度条回调函数类型和核心接口,方便后续扩展和复用:

#pragmaonce#include<stdio.h>#include<stdlib.h>#include<unistd.h>// 定义进度条回调函数类型:适配不同场景的进度刷新逻辑typedefvoid(*flush_t)(double total,double current,double speed,constchar* userinfo);// 彩色动态进度条核心接口// total:总进度(如文件总大小)// current:当前进度(如已下载大小)// speed:当前速度(如MB/s)// userinfo:附加信息(如单位)voidProcess_version(double total,double current,double speed,constchar*userinfo);

2.4 核心实现文件(process.c):关键逻辑代码剖析

集成颜色控制、进度计算、动态刷新,是进度条的核心:

#include"process.h"#include<string.h>// 进度条配置参数#defineSIZE103// 进度条缓冲区大小(适配100%+额外字符)#defineLABEL'='// 进度填充字符#defineCOLOR_GREEN"\033[32m"// 绿色#defineCOLOR_GRAY"\033[90m"// 灰色#defineCOLOR_CYAN"\033[36m"// 青色#defineCOLOR_RESET"\033[0m"// 重置颜色#defineCOLOR_RED"\033[31m"// 红色#defineCOLOR_YELLOW"\033[33m"// 黄色#defineCOLOR_BLUE"\033[34m"// 蓝色#defineCOLOR_MAGENTA"\033[35m"// 品红#defineCOLOR_WHITE"\033[97m"// 白色#defineCOLOR_BLACK"\033[30m"// 黑色// 彩色动态进度条实现voidProcess_version(double total,double current,double speed,constchar*userinfo){// 边界处理:当前进度超过总进度时直接返回if(current > total){return;}// 动态光标:循环切换,提示程序运行中staticconstchar*lable="|/-\\";staticint index =0;// 静态变量,记录光标位置,避免每次重置int size =strlen(lable);// 1. 计算比率double rate = current *100.0/ total;char out_bar[SIZE];memset(out_bar,'\0',sizeof(out_bar));// 2. 填充进度字符int i =0;for(; i <(int)rate; i++){ out_bar[i]= LABEL;}// 3. 彩色打印进度条(分颜色区分不同部分,视觉更清晰)// printf("[%-100s][%5.1lf%%][%c] | %.1lf/%.1lf,speed: %.1lf%s\r", out_bar,rate,lable[index],current,total,speed,userinfo);printf(COLOR_RED"[%-100s]",out_bar);// 进度主体(红色)printf(COLOR_BLUE"[%5.1lf%%]",rate);// 百分比(蓝色)printf(COLOR_CYAN"[%c]",lable[index]);// 动态光标(青色)printf(COLOR_YELLOW"| %.1lf/%.1lf,speed: %.1lf%s\r",current,total,speed,userinfo);// 附加信息(黄色)printf(COLOR_RESET);// 重置颜色,避免污染后续输出// 手动刷新缓冲区,确保内容实时显示fflush(stdout);// 更新光标索引(循环切换) index++; index %= size;// 4. 进度条完成,换行if(current >= total){printf("\r\n");}}// 正常颜色进度条实现//void Process_version(double total,double current,double speed,const char*userinfo)//{// if(current > total)// {// return;// }//// static const char *lable="|/-\\";// static int index = 0;// int size = strlen(lable);// // 1. 计算比率// double rate = current * 100.0 / total;// char out_bar[SIZE];// memset(out_bar, '\0', sizeof(out_bar));// // 2. 填充进度字符// int i = 0;// for(; i < (int)rate; i++)// {// out_bar[i] = LABEL;// }// // 3. 刷新进度条// printf("[%-100s][%5.1lf%%][%c] | %.1lf/%.1lf,speed: %.1lf%s\r", out_bar,rate,lable[index],current,total,speed,userinfo);// fflush(stdout);// index++;// index %= size;//// // 4. 进度条完成,换行// if(current >= total)// {// printf("\r\n");// }//}

2.5 主函数模块(main.c):应用场景测试

模拟多场景下载任务,测试进度条的适配性和稳定性:

#include"process.h"#include<unistd.h>#include<stdlib.h>#include<time.h>// 全局配置(可根据实际场景修改)double gtotal =1024.0;// 默认总进度(如1024MB)double gspeed =1.0;// 默认速度// 模拟下载任务:调用进度条回调函数刷新进度voidDownload(double total,flush_t cb){double current =0.0;// 模拟不同网络速度(模拟实际场景中速度波动)double level[]={0.01,0.05,10.0,20.0,24.0,38.0,50.0,68.9};int num =sizeof(level)/sizeof(level[0]);while(1){// 模拟下载耗时(1秒刷新一次)usleep(1000000);// 随机选择当前速度(模拟网络波动)double speed = level[rand()%num]; current += speed;// 边界处理:进度达到100%时终止if(current >= total){ current = total;// 确保进度不超过100%cb(total,current,speed,"MB/s");break;}else{// 刷新进度条cb(total,current,speed,"MB/s");}}// 这个跟proces.c中的第4步效果类似,写那个都行//printf("\n");}intmain(){// 初始化随机数种子,模拟速度波动srand(time(NULL));// 测试4个不同大小的下载任务,验证进度条适配性printf("download: \n");Download(gtotal,Process_version);printf("download: \n");Download(102.0,Process_version);printf("download: \n");Download(110.9,Process_version);printf("download: \n");Download(900.0,Process_version);return0;}

三. 操作实践与效果展示

实际操作过程

[Lotso@VM-4-4-centos lesson12--Progress]$ ll total 16 -rw-rw-r-- 1 Lotso Lotso 1620 Nov 2810:27 main.c -rw-rw-r-- 1 Lotso Lotso 344 Nov 28 08:55 Makefile -rw-rw-r-- 1 Lotso Lotso 3078 Nov 2810:22 process.c -rw-rw-r-- 1 Lotso Lotso 533 Nov 2810:22 process.h [Lotso@VM-4-4-centos lesson12--Progress]$ make compiling main.c to main.o compiling process.c to process.o main.o process.o link to process_bar [Lotso@VM-4-4-centos lesson12--Progress]$ ./process_bar download: [====================================================================================================][100.0%][|]|1024.0/1024.0,speed: 24.0MB/s download: [====================================================================================================][100.0%][\]|102.0/102.0,speed: 50.0MB/s download: [====================================================================================================][100.0%][-]|110.9/110.9,speed: 68.9MB/s download: [====================================================================================================][100.0%][/]|900.0/900.0,speed: 24.0MB/s [Lotso@VM-4-4-centos lesson12--Progress]$ make clean File cleanup complete 

执行./process_bar后,终端会输出 4 个下载任务的进度条,每个部分颜色区分清晰:

  • 红色:进度主体(=填充部分);
  • 蓝色:百分比(如50.0%);
  • 青色:动态光标(|/-\循环切换);
  • 黄色:附加信息(当前进度 / 总进度、传输速度);

进度完成后自动换行,后续任务不重叠,整体流畅无错乱。

注意:其中动态光标只与调用的这个函数有关,不管进度条动不动,他都是得转动的。还有就是大家如果想再优化一下的话可以试着把 = 替换成 色块 这样会更加清晰,其它的优化大家也可以自己想想尝试一下。

效果演示

彩色动态进度条


结尾:

🍓 我是草莓熊 Lotso!若这篇技术干货帮你打通了学习中的卡点: 👀 【关注】跟我一起深耕技术领域,从基础到进阶,见证每一次成长 ❤️ 【点赞】让优质内容被更多人看见,让知识传递更有力量 ⭐ 【收藏】把核心知识点、实战技巧存好,需要时直接查、随时用 💬 【评论】分享你的经验或疑问(比如曾踩过的技术坑?),一起交流避坑 🗳️ 【投票】用你的选择助力社区内容方向,告诉大家哪个技术点最该重点拆解 技术之路难免有困惑,但同行的人会让前进更有方向~愿我们都能在自己专注的领域里,一步步靠近心中的技术目标! 

结语:一个高质量的进度条,不仅是功能的补充,更是用户体验的提升。本文从基础原理到实战开发,再到优化扩展,带你吃透 Linux 终端进度条的核心逻辑,实现的彩色动态进度条可直接复用在下载、编译、数据处理等场景。掌握行缓冲区、回车换行、ANSI 颜色码等知识点后,你还可以举一反三,开发出更多终端交互工具(如倒计时、进度百分比动画)。Linux 终端开发的魅力就在于此 —— 看似简单的功能,背后藏着扎实的底层逻辑,吃透这些细节,才能写出更稳定、更优雅的代码。

✨把这些内容吃透超牛的!放松下吧✨ʕ˘ᴥ˘ʔづきらど

Read more

鸿蒙金融理财全栈项目——运维监控、性能优化、安全加固

鸿蒙金融理财全栈项目——运维监控、性能优化、安全加固

《鸿蒙APP开发从入门到精通》第20篇:鸿蒙金融理财全栈项目——运维监控、性能优化、安全加固 📊🔧🛡️ 内容承接与核心价值 这是《鸿蒙APP开发从入门到精通》的第20篇——运维监控、性能优化、安全加固篇,100%承接第19篇的生态合作、用户运营、数据变现架构,并基于金融场景的运维监控、性能优化、安全加固要求,设计并实现鸿蒙金融理财全栈项目的运维监控、性能优化、安全加固功能。 学习目标: * 掌握鸿蒙金融理财项目的运维监控设计与实现; * 实现应用监控、服务器监控、数据库监控; * 理解性能优化在金融场景的核心设计与实现; * 实现前端优化、后端优化、数据库优化; * 掌握安全加固在金融场景的设计与实现; * 实现代码加固、数据加密、安全审计; * 优化金融理财项目的用户体验(运维监控、性能优化、安全加固)。 学习重点: * 鸿蒙金融理财项目的运维监控设计原则; * 性能优化在金融场景的应用; * 安全加固在金融场景的设计要点。 一、 运维监控基础 🎯 1.1 运维监控定义 运维监控是指对金融理财项目的应用、

By Ne0inhk
【Linux篇】Socket编程UDP

【Linux篇】Socket编程UDP

📌 个人主页:孙同学_ 🔧 文章专栏:Liunx 💡 关注我,分享经验,助你少走弯路! 文章目录 * Socket编程UDP * 创建一个套接字 * 为套接字绑定一个端口号 * UDP套接字的初始化部分 * 收消息 * 发消息 * UDP通信流程拆分 * 简单演示: Socket编程UDP UDP是一种无连接、面向数据报、不可靠的传输层协议。具有不建立连接,不保证到达,不保证顺序,不重传,不拥塞控制,速度快,开销小 的特点。 我们想要网络通信,想要UDP的编写,我们想要以网络收发的话首先得把网络文件打开. 创建一个套接字 #include<sys/types.h>/* See NOTES */#include<sys/socket.h>intsocket(int domain,int

By Ne0inhk
OpenClaw 远程访问配置指南:SSH 隧道与免密登录

OpenClaw 远程访问配置指南:SSH 隧道与免密登录

OpenClaw 远程访问配置指南:SSH 隧道与免密登录 本文介绍如何从 Windows 访问部署在虚拟机/远程服务器上的 OpenClaw Gateway,包括 SSH 隧道配置和免密登录设置。 目录 1. 场景说明 2. SSH 隧道访问 3. 配置免密登录 4. 创建快捷启动脚本 5. 常见问题 一、场景说明 网络架构 ┌─────────────────────┐ ┌─────────────────────┐ │ Windows 主机 │ │ 虚拟机/服务器 │ │ │ SSH 隧道 │ │ │ 浏览器 ◄───────────┼───────────────────►│ OpenClaw Gateway │ │ localhost:18790 │ 端口转发 │ 127.0.0.1:18789 │ └─────────────────────┘ └─────────────────────┘ 为什么需要 SSH 隧道? OpenClaw Gateway

By Ne0inhk
【linux】linux进程概念(四)(环境变量)超详细版

【linux】linux进程概念(四)(环境变量)超详细版

小编个人主页详情<—请点击 小编个人gitee代码仓库<—请点击 linux系列专栏<—请点击 倘若命中无此运,孤身亦可登昆仑,送给屏幕面前的读者朋友们和小编自己! 目录 * 前言 * 一、基本概念 * 二、认识常见的几个环境变量 * echo $ 查看某个环境变量 * env 显示所有环境变量 * /dev/pts/0 字符设备 * HISTSIZE 默认保存的历史指令条数 * OLDPWD 保存上一次所处路径 * 三、测试PATH * 四、测试HOME和USER * 五、getenv 通过系统调用获取环境变量 * 六、命令行参数 * 指令的原型 * 打印命令行参数表 * 使用命令行第三个参数获取环境变量,打印环境变量表 * 七、环境变量为什么具有全局属性 * 理论 * 如何证明? * 八、命令分为常规命令和内建命令 * 内建命令的引出

By Ne0inhk