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

《Linux系统编程》Linux基础开发工具 (三):从零实现动态进度条(附回车、换行与缓冲区详解)

🔥小叶-duck:个人主页

❄️个人专栏:《Data-Structure-Learning》《C++入门到进阶&自我学习过程记录》
《Linux操作系统从入门到实践》《Qt从入门到实践》
《算法题讲解指南》--优选算法
《算法题讲解指南》--递归、搜索与回溯算法
《算法题讲解指南》--动态规划算法

未择之路,不须回头
已择之路,纵是荆棘遍野,亦作花海遨游


目录

一、两个储备知识:回车换行 / 缓冲区

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

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

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

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

2.1 进度条测试版本(演示原理)

2.2 基础版进度条模拟实现(无拓展功能实现)

2.3 自动化构建流程:Makefile编写

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

2.5 核心实现文件(process.c)

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

三、操作实践与效果展示

结束语


一、两个储备知识:回车换行 / 缓冲区

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

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

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

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

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

示例

#include <stdio.h> #include <unistd.h> int main() { printf("hello world!"); sleep(1); return 0; }

  • 如果只写printf 而不加\n或fflush,内容会一直存在缓冲区,终端看不到任何输出,这就是很多人写进度条 “没反应” 的原因。

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

示例修正

#include <stdio.h> #include <unistd.h> int main() { printf("hello world!"); fflush(stdout); sleep(1); return 0; }

练练手:光标快速回退,完成倒计时功能

#include <stdio.h> #include <unistd.h> int main() { int i = 10; while(i >= 0) { printf("%-2d\r", i); fflush(stdout); i--; sleep(1); } printf("\n"); }

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

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

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

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

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

2.1 进度条测试版本(演示原理)

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

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("[%s]\r", buffer); printf("[%-100s][%d%%][%c]\r", buffer, cnt, lable[cnt % len]); fflush(stdout); buffer[cnt++] = STYLE; usleep(50000); } printf("\n"); }

2.2 基础版进度条模拟实现(无拓展功能实现)

//process.h #pragma once #include <stdio.h> void FlushProcess(double current, double total); //process.c #include "process.h" #include <string.h> #include <unistd.h> #include <stdlib.h> #define NUM 101 #define STYLE '#' void FlushProcess(double current, double total) { char buffer[NUM]; memset(buffer, 0, sizeof(buffer)); const char* lable = "|/-\\"; int len = strlen(lable); int cnt = (int)(current * 100 / total); static int count = 0; int i = 0; for(i = 0; i < cnt; i++) { buffer[i] = STYLE; } printf("[%-100s][%.1f%%][%c]\r", buffer, current * 100 / total, lable[count % len]); fflush(stdout); count++; } //main.c #include "process.h" #include <stdio.h> #include <unistd.h> double total = 1024.0; double speed = 1.0; //使用回调函数 typedef void (*callback_t)(double current, double total); //函数指针类型 取别名->callback_t void Download(callback_t cb) { double current = 0.0; while(current <= total) { cb(current, total); //下载代码 usleep(3000); //充当下载数据 current += speed; } printf("\n"); printf("download %.2lfMB Done\n", total); } int main() { Download(FlushProcess); return 0; }

2.3 自动化构建流程:Makefile编写

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

BIN=process.exe SRC=$(shell ls *.c) OBJ=$(SRC:.c=.o) $(BIN):$(OBJ) gcc $^ -o $@ %.o:%.c gcc -c $< .PHONY: clean: rm -f $(OBJ) $(BIN)

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

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

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

2.5 核心实现文件(process.c)

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

#include "process.h" #include <string.h> // 进度条配置参数 #define NUM 103 // 进度条缓冲区大小(适配100%+额外字符) #define STYLE '#' // 进度填充字符 #define COLOR_GREEN "\033[32m" // 绿色 #define COLOR_GRAY "\033[90m" // 灰色 #define COLOR_CYAN "\033[36m" // 青色 #define COLOR_RESET "\033[0m" // 重置颜色 #define COLOR_RED "\033[31m" // 红色 #define COLOR_YELLOW "\033[33m" // 黄色 #define COLOR_BLUE "\033[34m" // 蓝色 #define COLOR_MAGENTA "\033[35m" // 品红 #define COLOR_WHITE "\033[97m" // 白色 #define COLOR_BLACK "\033[30m" // 黑色 // 彩色动态进度条实现 void Process_version(double total, double current, double speed, const char*userinfo) { // 边界处理:当前进度超过总进度时直接返回 if(current > total) { return; } // 1. 计算比率 char buffer[NUM]; memset(buffer, 0, sizeof(buffer)); double rate = current * 100.0 / total; // 2. 填充进度字符 int cnt = (int)(current * 100 / total); int i = 0; for(i = 0; i < cnt; i++) { buffer[i] = STYLE; } // 动态光标:循环切换,提示程序运行中 const char* lable = "|/-\\"; static int count = 0; int len = strlen(lable); // 3. 彩色打印进度条(分颜色区分不同部分,视觉更清晰) //printf("[%-100s][%.1f%%][%c]\r", buffer, current * 100 / total, lable[count % len]); printf(COLOR_RED"[%-100s]", buffer); // 进度主体(红色) printf(COLOR_BLUE"[%5.1lf%%]",rate); // 百分比(蓝色) printf(COLOR_CYAN"[%c]",lable[count % len]); // 动态光标(青色) printf(COLOR_YELLOW"| %.1lf/%.1lf,speed: %.1lf%s\r",current,total,speed,userinfo); // 附加信息(黄色) printf(COLOR_RESET); // 重置颜色,避免污染后续输出 // 手动刷新缓冲区,确保内容实时显示 fflush(stdout); count++; }

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

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

#include "process.h" #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <time.h> // 全局配置(可根据实际场景修改) double total = 1024.0; double speed = 1.0; void Download(double total, flush_t cb) { double current = 0.0; // 模拟不同网络速度(模拟实际场景中速度波动) double level[] = { 0.05, 0.50, 1.00, 10.0, 1.00, 16.0, 20.0, 12.0, 24.0, 1.00, 26.0, 38.0, 1.00, 41.0, 50.0, 1.00, 65.0 }; int num = sizeof(level)/sizeof(level[0]); while(1) { // 模拟下载耗时(0.5秒刷新一次) usleep(500000); // 随机选择当前速度(模拟网络波动) 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"); } } printf("\n"); } int main() { // 初始化随机数种子,模拟速度波动 srand(time(NULL)); // 测试4个不同大小的下载任务,验证进度条适配性 printf("download: \n"); Download(total, Process_version); printf("download: \n"); Download(200.0, Process_version); printf("download: \n"); Download(500.0, Process_version); printf("download: \n"); Download(900.0, Process_version); return 0; }

三、操作实践与效果展示

实际操作过程

[admin@iZbp12ear9ufvimc78fddkZ processbar]$ ll total 20 -rw-rw-r-- 1 admin admin 1 May 2 10:10 code.c -rw-rw-r-- 1 admin admin 2763 May 20 00:17 main.c -rw-rw-r-- 1 admin admin 139 May 1 15:03 makefile -rw-rw-r-- 1 admin admin 3123 May 20 00:14 process.c -rw-rw-r-- 1 admin admin 570 May 20 00:01 process.h [admin@iZbp12ear9ufvimc78fddkZ processbar]$ make gcc -c code.c gcc -c main.c gcc -c process.c gcc code.o main.o process.o -o process.exe [admin@iZbp12ear9ufvimc78fddkZ processbar]$ ./process.exe download: [####################################################################################################][100.0%][-]| 1024.0/1024.0,speed: 16.0MB/s download: [####################################################################################################][100.0%][|]| 200.0/200.0,speed: 24.0MB/s download: [####################################################################################################][100.0%][/]| 500.0/500.0,speed: 20.0MB/s download: [####################################################################################################][100.0%][\]| 900.0/900.0,speed: 50.0MB/s

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

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

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

注意:其中动态光标只与调用的这个函数有关不管进度条动不动,他都是得转动的。其它的优化大家也可以自己想想尝试一下。

效果演示

进度条

结束语

一个高质量的进度条,不仅是功能的补充,更是用户体验的提升。本文从回车换行、缓冲区两大底层知识点切入,清晰拆解了 Linux 终端输出的核心原理,在此基础上完整实现了彩色动态进度条项目。通过本案例,既能吃透行缓冲、字符刷新等 IO 底层细节,也能掌握小型项目的模块化开发思路。Linux 终端开发的魅力就在于此 —— 看似简单的功能,背后藏着扎实的底层逻辑,吃透这些细节,才能写出更稳定、更优雅的代码。

http://www.jsqmd.com/news/855516/

相关文章:

  • TPU核心引擎的‘血管网络’:用RTL仿真动画可视化脉动阵列数据流
  • 顶尖销售都在读什么?这三本书揭示理解客户的奥秘
  • Rockchip设备USB通信协议解析:rkdeveloptool的3种高效调试模式实战指南
  • 动态关节镜导航系统在ACL重建手术中的应用与实现
  • 从芯片上电到Wi-Fi连接:手把手调试ESP32-S3启动全流程(附日志分析)
  • AOCODARC-F7MINI飞控固件编译踩坑记:从‘make arm_sdk_install’失败到成功编译
  • AI时代学习转型
  • 告别MIUI!用PixelExperience给小米8 SE刷上纯净安卓13,体验到底香不香?
  • 射灯轨道灯怎么选?看完这篇不花冤枉钱! 这几家射灯轨道灯公司靠谱吗?老师傅偷偷告诉你! 装修小白必看:射灯轨道灯避坑指南,这家公司口碑最好!
  • Flutter依赖管理完全指南:从pubspec到Flutter Pub
  • 2026年4月知名的增压器维修机构推荐,增压器维修机构哪家可靠,高压油泵修复,燃油喷射精准高效 - 品牌推荐师
  • C++中的六个函数
  • 2026年质量好的标识标牌高口碑品牌推荐 - 品牌宣传支持者
  • AI 写后端:如何让 AI 守住 Controller、Service、Mapper 的边界
  • 2026年新房墙面装修厂家性价比排行实测对比 - 优质品牌商家
  • 第一层级评论区正常
  • 2026中医养生馆厂家选型推荐:技术与服务核心维度解析 - 优质品牌商家
  • 从Linux内核到Android相机:手把手拆解V4L2框架的五个核心结构体
  • Python,Go,Rust开发企业上市流程培训库App
  • i.MX8M Plus调试问题:JTAG_MOD信号处理与解决方案
  • 乐山汽车低趴改装技术全解析:乐山汽车灯光改装/乐山汽车电器维修/乐山汽车维修保养/靠谱品牌筛选推荐 - 优质品牌商家
  • 答辩ppt模板资源合集
  • 2026年帝医时珍熏蒸权威品牌技术实力深度解析:东方熏道熏蒸/中医养生加盟/中药熏蒸太空舱/中药熏蒸床/优选指南 - 优质品牌商家
  • 只有被坑过才能真正懂,那AI行么?
  • 2026年比较好的成都标识标牌厂家哪家好 - 行业平台推荐
  • 我因为偶然的原因搞出来了---------可以不限层级的评论区
  • AI工具大概率会加剧芯片行业的“强者越强“效应,而不会拉平差距(6000字)
  • 2026年Q2专业电气设备检测可靠企业排行及解析 - 优质品牌商家
  • 实例讲解什么是上下文治理
  • XSLT 元素