ZeroOne AI
← 返回文章列表

Linux系统篇(九)——C 语言实战:终端实时刷新进度条

👁 5
分类:工业互联网

手把手用 C 语言在 Linux 终端实现实时刷新进度条,讲透回车换行区别、行缓冲区与 fflush 强制刷新机制

项目背景

很多刚接触 Linux C 编程的同学,都会想做一个能在终端里"动起来"的程序——比如下载时那种从左到右填充、旁边还带旋转动画和百分比数字的进度条。这不仅是练习 C 语言基本功的好素材,更能在动手过程中把 \r(回车)、\n(换行)以及行缓冲区这些平时容易混淆的概念彻底搞懂。

本文从零开始,先讲清两个关键概念,再手写一个倒计时程序练手,最后给出完整可运行的进度条实现,帮助读者打通"终端字符控制"这条技能线。

技术方案

1. 回车 \r 与换行 \n 的区别

这两个符号的起源要追溯到老式打字机:

要在终端实现"原地刷新"效果,必须用 \r:它让光标回到行首,下一次打印的新内容就会覆盖上一次的内容,从而形成动态更新的视觉体验。如果误用 \n,进度条就会不断向下换行,变成"刷屏"而非"刷新"。

2. 行缓冲区的坑

在 C 语言中,printf 默认是行缓冲模式:只有当输出遇到 \n 换行符、程序正常结束,或者缓冲区被写满时,内容才会真正被送往终端。如果我们在循环里不断 printf 却不带换行、不刷新,屏幕上将什么都看不到。

解决办法有两个:

3. 先练手:倒计时程序

在实现进度条之前,先用一个 100 秒倒计时验证 \r + 刷新的组合思路:

#include <stdio.h>
#include <windows.h>  // 仅 Windows 演示用;Linux 下建议用 usleep()

int main()
{
    int time = 100;
    while (time >= 0)
    {
        // %-3d 左对齐占 3 位,避免位数变化时残留旧字符
        printf("%-3d\r", time);
        fflush(stdout);      // 强制刷新,立即显示
        Sleep(1000);         // 等待 1 秒
        time--;
    }
    printf("\n");
    return 0;
}

可以看到:\r 让数字始终在同一位置跳动,fflush 保证每次更新都能及时显示。

系统架构

进度条程序整体上是一个"刷新循环 + 状态映射"的结构,核心模块拆解如下:

模块职责实现要点
进度填充 buffer存放已完成的进度符号字符数组,按百分比填充 #
旋转动画 stat展示"正在工作"的指示器字符串 `"
进度映射 rate把当前量换算成百分比current / total 再乘 100
刷新输出覆盖上一帧画面\r 回行首 + fflush 强制上屏

实施过程

1. 头文件与接口声明

// proce.h
#ifndef __PROCE_H__
#define __PROCE_H__

#include <stdio.h>
#include <unistd.h>
#include <string.h>

#define N 101      // 进度条最大宽度(100 格 + 结束符)
#define STATE '#'  // 进度填充字符

void process();
void FlushProcess(double total, double current);

#endif

2. 核心刷新函数

// proce.c
#include "proce.h"

// 依据当前进度,刷新一次进度条显示
void FlushProcess(double total, double current)
{
    char buffer[N];                    // 进度填充缓冲区
    const char* stat = "|/-\\";        // 旋转动画字符集
    memset(buffer, 0, sizeof(buffer)); // 先清空

    int len = strlen(stat);            // 动画字符个数
    int num = (int)(current * 100 / total); // 已完成的格数

    // 填充进度条主体
    for (int i = 0; i <= num; i++)
    {
        buffer[i] = STATE;
    }

    double rate = current / total;     // 进度比例
    static int cnt = 0;                // 动画游标(静态变量跨调用保持)
    cnt %= len;

    // %-100s 左对齐占 100 格;%% 转义输出百分号
    printf("[%-100s][%d%%][%c]\r", buffer, (int)(rate * 100), stat[cnt]);
    cnt++;

    fflush(stdout);                    // 关键:立即刷新到终端
}

3. 主流程:模拟下载

int main()
{
    const double total = 100.0;   // 任务总量
    const double speed = 2.0;     // 每次推进的速度
    double current = 0;           // 当前完成量

    while (current <= total)
    {
        FlushProcess(total, current);
        usleep(3000);             // 暂停 3ms,模拟耗时操作
        current += speed;
    }

    printf("\n");
    printf("\ndownload %.2lfMB Done\n", current);
    return 0;
}

运行效果:进度条从左向右填充,右侧百分比同步增长,末尾的 | / - \ 旋转动画循环转动,全程在同一行内完成刷新,体验十分顺滑。

应用价值

SEO关键词

Linux, C语言, 进度条, 回车换行, 行缓冲区, fflush, 终端编程, printf

评论(0