一、ANSI 转义序列:终端色彩与光标控制
Linux 终端支持 ANSI 转义序列,可以实现文字着色、光标移动、清除行等高级效果,是美化进度条的基础。
1.1 常用颜色码(前景色)
| 颜色 | 代码 | 颜色 | 代码 |
|---|---|---|---|
| 黑色 | 30 | 红色 | 31 |
| 绿色 | 32 | 黄色 | 33 |
| 蓝色 | 34 | 紫色 | 35 |
| 青色 | 36 | 白色 | 37 |
1.2 常用光标 / 清屏控制
\033[K:清除光标位置到行尾的内容\033[2K:清除整行内容\033[nA:光标向上移动 n 行\033[nB:光标向下移动 n 行
二、版本 4:彩色动态进度条
加入绿色进度条、百分比高亮、完成后变色提示,视觉效果大幅提升。
cpp
#include <iostream>
#include <unistd.h>
#include <string>
const int BAR_LEN = 50;
// ANSI 颜色宏
#define COLOR_GREEN "\033[32m"
#define COLOR_YELLOW "\033[33m"
#define COLOR_RED "\033[31m"
#define COLOR_RESET "\033[0m"
int main() {
for (int i = 0; i <= 100; ++i) {
int fill = i * BAR_LEN / 100;
std::cout << "\r" COLOR_GREEN "[";
// 填充部分用绿色
for (int j = 0; j < fill; ++j) {
std::cout << "=";
}
// 箭头用黄色
if (fill < BAR_LEN) {
std::cout << COLOR_YELLOW ">";
}
// 空白部分重置颜色
std::cout << COLOR_RESET;
for (int j = fill + 1; j < BAR_LEN; ++j) {
std::cout << " ";
}
// 百分比数字高亮
if (i == 100) {
std::cout << COLOR_GREEN "] " << i << "% 完成" COLOR_RESET;
} else {
std::cout << "] " COLOR_YELLOW << i << "%" COLOR_RESET;
}
std::cout.flush();
usleep(40000);
}
std::cout << std::endl;
return 0;
}
三、版本 5:带速度与剩余时间估算的进度条
模拟真实任务场景,加入已处理量 / 总量、处理速度、预计剩余时间(ETA),是工程中最实用的版本。
cpp
#include <iostream>
#include <unistd.h>
#include <time.h>
#include <string>
const int BAR_LEN = 40;
#define COLOR_GREEN "\033[32m"
#define COLOR_YELLOW "\033[33m"
#define COLOR_CYAN "\033[36m"
#define COLOR_RESET "\033[0m"
int main() {
const int total = 200; // 模拟总任务量
time_t start_time = time(NULL);
for (int i = 0; i <= total; ++i) {
// 计算进度百分比
double percent = (double)i / total * 100;
int fill = (int)(percent * BAR_LEN / 100);
// 计算速度和剩余时间
time_t now = time(NULL);
double elapsed = difftime(now, start_time);
double speed = (elapsed > 0) ? (i / elapsed) : 0;
int eta = (speed > 0) ? (int)((total - i) / speed) : 0;
// 输出进度条
printf("\r" COLOR_GREEN "[" COLOR_RESET);
for (int j = 0; j < fill; ++j) printf("=");
if (fill < BAR_LEN) printf(COLOR_YELLOW ">" COLOR_RESET);
for (int j = fill + 1; j < BAR_LEN; ++j) printf(" ");
printf("] ");
// 输出详细信息:百分比、已完成/总量、速度、剩余时间
printf(COLOR_YELLOW "%5.1f%%" COLOR_RESET " ", percent);
printf("%d/%d ", i, total);
printf(COLOR_CYAN "%.1f 个/秒" COLOR_RESET " ", speed);
printf("剩余: %d秒", eta);
fflush(stdout);
usleep(30000); // 模拟每个任务单元的耗时
}
printf("\n");
return 0;
}
实现逻辑说明
- 速度计算 :
速度 = 已完成数量 / 已用时间 - 剩余时间估算 :
ETA = (总量 - 已完成量) / 速度 - 使用
time()函数获取系统时间,difftime()计算时间差,单位为秒。 - 适合文件下载、批量处理、数据导入等真实业务场景。
四、版本 6:C++ 类封装工程版
将进度条封装为 ProgressBar 类,支持自定义样式、颜色、总长度,可直接嵌入项目复用
cpp
#ifndef PROGRESS_BAR_H
#define PROGRESS_BAR_H
#include <string>
#include <time.h>
class ProgressBar {
public:
// 构造函数:总任务量、进度条宽度、样式字符
ProgressBar(int total, int width = 50, char fill_char = '=', char arrow_char = '>');
// 更新进度:传入当前已完成量
void update(int current);
// 手动设置完成并换行
void finish();
// 是否已经完成
bool is_finished() const { return finished_; }
private:
int total_; // 总任务量
int width_; // 进度条宽度
char fill_char_; // 填充字符
char arrow_char_; // 箭头字符
int current_; // 当前完成量
bool finished_; // 是否完成
time_t start_; // 开始时间
// 格式化时间显示
std::string format_time(int seconds) const;
};
#endif
cpp
#ifndef PROGRESS_BAR_H
#define PROGRESS_BAR_H
#include <string>
#include <time.h>
class ProgressBar {
public:
// 构造函数:总任务量、进度条宽度、样式字符
ProgressBar(int total, int width = 50, char fill_char = '=', char arrow_char = '>');
// 更新进度:传入当前已完成量
void update(int current);
// 手动设置完成并换行
void finish();
// 是否已经完成
bool is_finished() const { return finished_; }
private:
int total_; // 总任务量
int width_; // 进度条宽度
char fill_char_; // 填充字符
char arrow_char_; // 箭头字符
int current_; // 当前完成量
bool finished_; // 是否完成
time_t start_; // 开始时间
// 格式化时间显示
std::string format_time(int seconds) const;
};
#endif
使用示例 main.cpp
cpp
#include "progress_bar.h"
#include <unistd.h>
int main() {
const int TOTAL = 500;
ProgressBar bar(TOTAL, 60, '#', '>');
for (int i = 0; i <= TOTAL; ++i) {
bar.update(i);
usleep(10000);
}
return 0;
}
编译运行:
cpp
g++ main.cpp progress_bar.cpp -o progress_bar
./progress_bar
五、进阶扩展:旋转等待指示器
当任务总量未知、只能显示 "正在运行" 时,使用旋转字符动画(| / - \)替代进度条。
cpp
#include <iostream>
#include <unistd.h>
int main() {
const char spinner[] = {'|', '/', '-', '\\'};
int idx = 0;
std::cout << "正在处理中... ";
for (int i = 0; i < 30; ++i) { // 模拟30次循环
printf("\b%c", spinner[idx % 4]);
fflush(stdout);
idx++;
usleep(150000);
}
printf("\b完成\n");
return 0;
}
六、核心总结与注意事项
- ANSI 转义序列是 Linux 终端美化的核心,所有主流终端均兼容。
- 工程化使用时建议封装为类,支持自定义样式、自动计算速度与 ETA。
- 总量未知场景可用旋转指示器替代固定进度条。
- 注意事项:
- 重定向输出到文件时,ANSI 颜色码会变成乱码,生产环境可加判断禁用颜色。
- 进度更新不要过于频繁(比如每毫秒刷新一次),避免占用过多 CPU。
- 多线程环境下使用进度条需要加锁,防止输出错乱。
谢谢