如何在 Linux 终端中复制 wget 类似的速度界面?

3
Wget会在文件下载时以非常清晰的方式将速度信息打印到stdout,其中速度显示并刷新,屏幕上滚动着一个进度条。我想在Python程序中复制这种输出方式。这是否可能?
我认为curses库应该能够做到这一点;以下是我想到的:-
import curses, time

class Speeder( object ):
    """Show and refresh time and download speed in a curses interface."""
    t1 = 0. # start time
    t  = 0. # current time
    tf = 0. # end time
    def start(self, filename=None ):
        """Start timer"""
        self.t1 = self.t = time.time()
        curses.use_env(True)
        curses.initscr()
        self.win = curses.newwin(4, 0)
        if filename is not None:
            self.win.addnstr(filename, 50 )
            self.win.refresh()

    def update(self, rbytes):
        """Refresh speed."""
        t = time.time()
        td = t - self.t
        self.t = t
        speed = rbytes / td 
        self.win.addstr(0,54,str('{0:.02f} B/s'.format(speed)))
        self.win.refresh()

    def end(self):
        """End timer"""
        self.tf = time.time() 
        curses.endwin()


try:
    speed = Speeder()
    speed.start(filename='foo.bar')
    for i in xrange(10):
        time.sleep(0.5)
        speed.update(200)
finally:
    speed.end()

问题在于它占用了整个窗口,而我只需要一行。我不想把所有的命令行历史记录都推到终端窗口上方。请纠正我如果我错了,但我目前认为curses应用程序总是占用整个终端窗口。
所以我看了一下tty和termios模块,但我找不到任何做我想做的事情的例子。
最后,我发现一个博客文章通过向sys.stdout写入一些特殊字符来完成此操作。将他的代码应用到我的Speeder类中,我得到了这个:-
import sys
class Speeder( object ):
    """Show and refresh time and download speed."""
    t1 = 0. # start time
    t  = 0. # current time
    tf = 0. # end time
    def start(self, filename=None ):
        """Start timer"""
        self.t1 = self.t = time.time()
        if filename is not None:
            sys.stdout.write( '\r\x1b[K' + filename.ljust(50) )
            sys.stdout.flush()

    def update(self, rbytes):
        """Refresh speed."""
        t = time.time()
        td = t - self.t
        self.t = t
        speed = '{0} B/s'.format( rbytes / td )
        sys.stdout.write( "\r\x1b[K" + speed.rjust(65) )
        sys.stdout.flush()

    def end(self):
        """End timer"""
        self.tf = time.time()
        sys.stdout.write('\n')

这段代码行数较少,我喜欢这一点,但是说实话,我不知道正在发生什么,也不知道如何修改它以仅更新行的一部分,类似于curses.addstr函数。目前,文件名被覆盖为白色空格。当然,我可以修改类以每次从Python构造整个行,但我想理解它以便根据自己的需要进行调整。
作者说这只有在VT100终端上才可能。那么我猜这只能在Unix终端上工作?那很好,但是有没有任何Unix终端无法使用这个功能?
关于此主题是否有更好的文档或更复杂的示例(例如,更新多行,其中一行中的一行或单行中的单个字符),最好是针对Python?这似乎不是Python的一个特性,而是tty,这就是我猜测为什么我找不到任何东西的原因。是否有man页或其他应该阅读的内容?
2个回答

4

谢谢,我现在开始欣赏 ANSI 转义码,并已经找出如何使用它们移动光标。将上面的 update 方法中的转义码替换为 "\033[15D",让我可以将光标向后移动 15 个字符。然后我就可以覆盖已经存在的内容了。完美! - Alex Leach
给你正确的答案是为了感谢你帮我找到似乎最简单的解决方案。 - Alex Leach

2
您可能想看看Blessings,它似乎正是你想要的:

Blessings解除了curses的一些限制性假设,而且它还可以使您的代码更漂亮。


祝福看起来真的很棒!尤其是它提供的示例代码!感谢您的推荐。 - Alex Leach
当它在一段时间以前在/r/Python上随机出现时,我也有同样的想法。 - mensi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接