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


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


🎬 博主简介:


文章目录

  • 前言:
  • [一. 核心预备知识:掌握三大关键点,轻松避开进度条开发常见误区](#一. 核心预备知识:掌握三大关键点,轻松避开进度条开发常见误区)
    • [1.1 回车(\r)与换行(\n)的本质区别解析](#1.1 回车(\r)与换行(\n)的本质区别解析)
    • [1.2 深入理解行缓冲区运行机制](#1.2 深入理解行缓冲区运行机制)
    • [1.3 进度条的核心构成元素详解](#1.3 进度条的核心构成元素详解)
  • [二. 实战开发:打造动态彩色进度条](#二. 实战开发:打造动态彩色进度条)
    • [2.1 基础版进度条模拟实现(演示原理,实际应用较少)](#2.1 基础版进度条模拟实现(演示原理,实际应用较少))
    • [2.2 自动化构建流程:Makefile编写详解](#2.2 自动化构建流程:Makefile编写详解)
    • [2.3 头文件设计(process.h):接口函数声明](#2.3 头文件设计(process.h):接口函数声明)
    • [2.4 核心实现文件(process.c):关键逻辑代码剖析](#2.4 核心实现文件(process.c):关键逻辑代码剖析)
    • [2.5 主函数模块(main.c):应用场景测试](#2.5 主函数模块(main.c):应用场景测试)
  • [三. 操作实践与效果展示](#三. 操作实践与效果展示)
  • 结尾:

前言:

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


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

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

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

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

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

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

错误示例

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

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

示例修正

cpp 复制代码
#include <stdio.h>
int main() 
{
    printf("hello bite!");
    fflush(stdout);
    sleep(3);
    return 0;
}

练手倒计时小程序:

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

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

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

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

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

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

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

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

cpp 复制代码
#include "process.h"
#include <string.h>
#include <unistd.h>
#define NUM 101
#define STYLE '='
// vesion1
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][%d%%][%c]\r", buffer, cnt, lable[cnt % len]);
        fflush(stdout);
        buffer[cnt] = STYLE;
        cnt++;
        usleep(50000);
    }
    printf("\n");
}

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

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

bash 复制代码
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):接口函数声明

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

cpp 复制代码
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

// 定义进度条回调函数类型:适配不同场景的进度刷新逻辑
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.4 核心实现文件(process.c):关键逻辑代码剖析

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

cpp 复制代码
#include"process.h"
#include<string.h>

// 进度条配置参数
#define SIZE 103     // 进度条缓冲区大小(适配100%+额外字符)
#define LABEL '='    // 进度填充字符

#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;
    }

    // 动态光标:循环切换,提示程序运行中
    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);
    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):应用场景测试

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

cpp 复制代码
#include"process.h"
#include<unistd.h>
#include<stdlib.h>
#include<time.h>


// 全局配置(可根据实际场景修改)
double gtotal = 1024.0;  // 默认总进度(如1024MB)
double gspeed = 1.0;     // 默认速度

// 模拟下载任务:调用进度条回调函数刷新进度
void Download(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");
}
int main()
{
    // 初始化随机数种子,模拟速度波动
    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);

    return 0;
}

三. 操作实践与效果展示

实际操作过程

bash 复制代码
[Lotso@VM-4-4-centos lesson12--Progress]$ ll
total 16
-rw-rw-r-- 1 Lotso Lotso 1620 Nov 28 10:27 main.c
-rw-rw-r-- 1 Lotso Lotso  344 Nov 28 08:55 Makefile
-rw-rw-r-- 1 Lotso Lotso 3078 Nov 28 10:22 process.c
-rw-rw-r-- 1 Lotso Lotso  533 Nov 28 10: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%);
  • 青色 :动态光标(| / - \循环切换);
  • 黄色:附加信息(当前进度 / 总进度、传输速度);

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

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

效果演示

彩色动态进度条


结尾:

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

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

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

相关推荐
大柏怎么被偷了2 小时前
【Linux】动静态库
linux
百泰派克生物科技2 小时前
串联质量标签(TMT)
人工智能·机器学习·蛋白质组学·蛋白质·质谱
行稳方能走远3 小时前
Android C++ 学习笔记3
android·c++
渡我白衣3 小时前
多路转接之epoll:理论篇
人工智能·神经网络·网络协议·tcp/ip·自然语言处理·信息与通信·tcpdump
明月照山海-3 小时前
机器学习周报二十八
人工智能·机器学习
weixin_437497779 小时前
读书笔记:Context Engineering 2.0 (上)
人工智能·nlp
程途拾光1589 小时前
企业部门协作泳道图制作工具 PC端
大数据·运维·流程图
喝拿铁写前端9 小时前
前端开发者使用 AI 的能力层级——从表面使用到工程化能力的真正分水岭
前端·人工智能·程序员
goodfat9 小时前
Win11如何关闭自动更新 Win11暂停系统更新的设置方法【教程】
人工智能·禁止windows更新·win11优化工具