C++ 如何从 cout 回滚行?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3277058/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to rollback lines from cout?
提问by Mister Mystère
I'm coding a task monitoring, which updates tasks' progress using cout. I'd like to display one task progress per line, therefore I have to rollback several lines of the console.
我正在编写一个任务监控,它使用 cout 更新任务的进度。我想每行显示一个任务进度,因此我必须回滚控制台的几行。
I insist on "several" because \b
does the job for one line, but does not erase \n
between lines.
我坚持“几个”,因为\b
可以为一行完成工作,但不会在行\n
之间擦除。
I tried std::cout.seekp(std::cout.tellp() - str.length());
but tellp()
returns -1 (failure).
我试过std::cout.seekp(std::cout.tellp() - str.length());
但tellp()
返回 -1(失败)。
回答by pts
You can do cout << '\r';
to jump to the beginning of the current line, but moving upwards is system-specific. For Unix, see man termcap
and man terminfo
(and search for cursor_up
). On ANSI-compatible terminals (such as most modern terminals available on Unix), this works to move up: cout << "\e[A";
.
您可以cout << '\r';
跳到当前行的开头,但向上移动是特定于系统的。对于 Unix,请参阅man termcap
和man terminfo
(并搜索cursor_up
)。在兼容 ANSI 的终端(例如 Unix 上可用的大多数现代终端)上,这可以向上移动:cout << "\e[A";
.
Don't try seeking in cout
, it's unseekable most of the time (except when redirected to a file).
不要尝试寻找 in cout
,它在大多数情况下是不可搜索的(除非重定向到文件)。
As mentioned in other answers, using the ncurses(or slang) library provides a good abstraction for terminal I/O on Unix.
正如其他答案中提到的,使用ncurses(或slang)库为 Unix 上的终端 I/O 提供了一个很好的抽象。
Instead of filling with spaces (which is error-prone, because not every terminal is 80 characters wide), you can do \r
+ clr_eol
: std::cout << "\r\e[K" << std::flush
.
而不是填充空格(这很容易出错,因为不是每个终端都是 80 个字符宽),你可以做\r
+ clr_eol
: std::cout << "\r\e[K" << std::flush
。
回答by You
回答by Nikolai Fetissov
回答by Erroneous
I know this is an old post, but the accepted doesn't cover cases where cout is piped to a program or file and this is the top of my google searches. The following will handle both piped and non-piped stdout with slightly different behavior.
我知道这是一篇旧帖子,但接受的内容不包括将 cout 通过管道传输到程序或文件的情况,这是我的谷歌搜索的顶部。以下将处理管道和非管道标准输出,行为略有不同。
#include <iostream>
#include <functional>
#include <stdio.h>
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#define _isatty isatty
#define _fileno fileno
#endif
const std::function<void(const size_t&)> progress_printer(_isatty(_fileno(stdout)) == 1 ?
[](const size_t& i) {
std::cout << "\rNumber " << i << std::flush;
} :
[](const size_t& i) {
static std::ios::off_type last(-1);
if(last != -1)
std::cout.seekp(last, std::ios::beg);
last = std::cout.tellp();
std::cout << "Number " << i << std::endl;
}
);
This is untested on windows, but should work. What it does is detect if the file descriptor or is a tty. If it is then it just writes '\r' if the pos hasn't changed since last time it printed or a newline. If it isn't a newline, it seeks to the last place it was after it printed.
这在 Windows 上未经测试,但应该可以工作。它的作用是检测文件描述符是否为 tty。如果是,那么它只是写 '\r' 如果自上次打印或换行以来 pos 没有改变。如果它不是换行符,它会寻找它打印后的最后一个位置。
It behaves differently for files than for tty. For a file, if something outputs to the stream between prints then it can overwrite some or all of what was written even after newlines. For ttys it just overwrites the chars at the beginning of the current line.
它对文件的行为与对 tty 的行为不同。对于文件,如果某些内容输出到打印之间的流,那么即使在换行符之后它也可以覆盖部分或全部写入的内容。对于 ttys,它只是覆盖当前行开头的字符。
回答by Alex Xu
Hope it helps ;) [It should work on Linux.]
希望它有所帮助;) [它应该可以在 Linux 上运行。]
// "\e[0K" Clear line from cursor to the end
cout << "\e[A\r\e[0K"<<what_you_want<<endl;
回答by Julian David Trejos Rueda
You can use first system(" "); for you can use \e[A (Dev-C++) or \u001B[A (Visual Studio)
您可以使用第一个 system(" "); 因为你可以使用 \e[A (Dev-C++) 或 \u001B[A (Visual Studio)
#include <iostream>
using namespace std;
int main()
{
system(" ");
string Input;
do
{
cout << "[#][\e[s";
cin >> Input;
cout << "[\e[u" << Input << "]"<<endl;
} while (2==2);
return 0;
}