你有没有注意过,运行一些命令行程序时,终端里的进度条看起来是“动”的?它们不是一行一行往下刷,而是在同一行上不断更新。
👀 那它们是怎么做到的呢?今天我们就来揭开这个小魔法的原理,并用 C++ 实现一个动态终端输出的示例。
✨ 魔法来自 ANSI 转义序列
我们可以使用以下神秘字符:
std::cout << "\033[2K\r";
这串字符其实是一个ANSI 转义序列,专门用来控制终端的显示效果,比如颜色、光标位置、清除屏幕等。
拆解一下这个组合技:
序列 | 含义 |
---|---|
\033 或 \x1b | ESC 字符,ANSI 转义的开始 |
[2K | 清除整行 |
\r | 回到行首 |
组合在一起就是:
✅ 清除当前行 + 把光标拉回行首
🧪 试试这个小 demo 吧
下面我们来写一个动态刷新进度百分比的 C++ 程序:
#include <iostream>
#include <chrono>
#include <thread>
int main() {
for (int i = 0; i <= 100; i++) {
std::cout << "\033[2K\r"; // 清除当前行
std::cout << "Progress: " << i << "%" << std::flush; // 输出新内容
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟耗时
}
std::cout << std::endl;
return 0;
}
效果展示:
🧼 来个进阶版
这次我们要写个真的进度条,并且添加上颜色:
#include <iostream>
#include <chrono>
#include <thread>
// 颜色代码
#define COLOR_GREEN "\033[32m"
#define COLOR_RESET "\033[0m"
// 清除行并回到开头
#define CLEAR_LINE "\033[2K\r"
// 输出进度条的函数
void PrintProgressBar(int progress, int total, int barWidth = 50) {
float ratio = static_cast<float>(progress) / total;
int filledLength = static_cast<int>(barWidth * ratio);
std::cout << CLEAR_LINE; // 清除当前行
std::cout << "Progress [";
std::cout << COLOR_GREEN;
for (int i = 0; i < filledLength; ++i) {
std::cout << "#";
}
std::cout << COLOR_RESET;
for (int i = filledLength; i < barWidth; ++i) {
std::cout << " ";
}
std::cout << "] " << static_cast<int>(ratio * 100) << "%" << std::flush;
}
int main() {
const int total = 100;
for (int i = 0; i <= total; ++i) {
PrintProgressBar(i, total);
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
std::cout << std::endl;
return 0;
}
效果展示:
📌 总结
这个小技巧可以帮我们实现一些状态刷新的功能或者写一些炫酷的命令行动画 ,快来试试吧!🌀
本文首发于微信公众号《Linux在秋名山》,欢迎大家关注~