倒带 std::cout 以回到行首
Posted
技术标签:
【中文标题】倒带 std::cout 以回到行首【英文标题】:Rewinding std::cout to go back to the beginning of a line 【发布时间】:2011-03-04 17:34:51 【问题描述】:我正在为 Mac OS X 编写一个用于处理一堆文件的命令行工具。我想向用户显示当前正在处理的文件,但不希望大量文件污染终端窗口。
相反,我想使用一行来输出文件路径,然后将该行重用于下一个文件。是否有要输出到std::cout
的字符(或其他代码)来完成此操作?
另外,如果我想将此工具重新定位到 Windows,两个平台的解决方案是否相同?
【问题讨论】:
【参考方案1】:"\r" 应该适用于 windows 和 Mac OS X。
类似:
std::cout << "will not see this\rwill see this" << std::flush;
std::cout << std::endl; // all done
【讨论】:
... 和 Linux,以及几乎所有其他东西。我认为理论上仍然无法正确处理此问题的唯一平台是 Mac OS 的 pre-X 版本。 这实际上会打印“”会看到这个这个“ 我的意思是,我也希望它能够工作,但后来我把你的代码放在 cpp.sh 中,它返回“不会看到这个会看到这个”,见cpp.sh/3kgrm。这是cpp.sh方面的错误吗?认为他们使用最新的标准编译器。 不要flush
在endl
之前,因为它包含一个隐含的flush
。事实上,当你不必立即输出时,根本不要使用endl
或flush
。对于换行符,只需使用'\n'
。流最迟在销毁时会刷新。
@Aziuth:问题不在于编译器,而是 cpp.sh 获取进程标准输出并将其呈现在浏览器中的代码不支持 \r ,就像普通的命令行终端一样.【参考方案2】:
我无法访问 mac,但从纯控制台的角度来看,这在很大程度上取决于它如何处理回车符和换行符。如果您可以从字面上将一个或另一个发送到控制台,那么您希望发送只是一个回车。
我很确定 Mac 对待回车和换行的方式与 *nix 和 windows 不同。
如果您正在寻找就地更新(例如覆盖当前行),我建议您查看 curses
库。这应该提供一个独立于平台的方法来做你正在寻找的事情。 (因为,即使使用标准 C++,也没有与平台无关的方法来满足您的要求)。
【讨论】:
Mac 使用 将 CR 与 Win/Unix 区别开来,当时它还不是 Unix 本身。但现在是这样,这个问题已经消失了。【参考方案3】:正如 Nathan Ernst 的回答所说,如果你想要一个健壮、正确的方法来做到这一点,请使用 curses - 特别是 ncurses。
如果您想要一种容易奏效且省力的 hackish 方式,请继续...
Linux、UNIX、MacOS、Windows 等的命令行终端倾向于支持一小组基本的 ASCII 控制字符,包括十进制字符 13 - 称为回车和 encoded in C++ 为 '\r' 或等效八进制 '\015' 或十六进制 '\x0D' - 指示终端返回到行首。
你通常想做的是……
int line_width = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 80;
std::string spacesline_width - 1, ' ';
for (const auto& filename : filenames)
std::cout << '\r' << spaces << '\r' << filename << std::flush;
process_file(filename);
std::cout << std::endl; // move past last filename...
这会在写入下一个文件名之前使用一串空格覆盖旧文件名,因此如果您的文件名较短,则不会看到较早的较长文件名的尾随字符。
std::flush
确保 C++ 程序在开始处理文件之前调用 OS write()
函数将文本发送到终端。否则,更新所需的文本 - \r
、空格、\r
和文件名 - 将附加到缓冲区并仅写入操作系统 - 例如4k 块 - 当缓冲区已满时,显示的文件名将落后于正在处理的实际文件的数十个文件。此外,假设缓冲区是 4k - 4096 字节 - 并且在某些时候你有 4080 字节缓冲,然后输出下一个文件名的文本:你最终会得到 \r
和缓冲区中适合的 15 个空格,当自动 - flushed 最终会清除屏幕上该行的前 15 个字符,并保留前一个文件名的其余部分(如果它长于 15 个字符),然后等到缓冲区再次满后再更新屏幕(仍然是随意的) .
最后的std::endl
只是将光标从你打印文件名的那一行移开,这样你就可以写“全部完成”,或者离开main()
并让shell 提示符显示在一个漂亮干净的行上,而不是可能覆盖您最后一个文件名的一部分(像 zsh 这样的伟大 shell 会检查这个)。
【讨论】:
以上是关于倒带 std::cout 以回到行首的主要内容,如果未能解决你的问题,请参考以下文章