我编写了一个简单的控制台应用程序,使用ftplib从FTP服务器上传和下载文件。
我想应用程序显示一些可视化的下载/上传进度为用户;每次下载数据块时,我希望它提供一个进度更新,即使它只是一个数字表示,如百分比。
重要的是,我想避免擦除之前打印到控制台的所有文本(即,我不想在打印更新的进度时“清除”整个终端)。
这似乎是一个相当常见的任务——我如何才能制作一个进度条或类似的可视化输出到我的控制台,同时保留之前的程序输出?
我编写了一个简单的控制台应用程序,使用ftplib从FTP服务器上传和下载文件。
我想应用程序显示一些可视化的下载/上传进度为用户;每次下载数据块时,我希望它提供一个进度更新,即使它只是一个数字表示,如百分比。
重要的是,我想避免擦除之前打印到控制台的所有文本(即,我不想在打印更新的进度时“清除”整个终端)。
这似乎是一个相当常见的任务——我如何才能制作一个进度条或类似的可视化输出到我的控制台,同时保留之前的程序输出?
当前回答
我意识到我在游戏中迟到了,但这里是我写的一个稍微有点yum风格的(Red Hat)(这里不是100%的准确性,但如果你使用进度条来达到这个准确度,那么你就错了):
import sys
def cli_progress_test(end_val, bar_length=20):
for i in xrange(0, end_val):
percent = float(i) / end_val
hashes = '#' * int(round(percent * bar_length))
spaces = ' ' * (bar_length - len(hashes))
sys.stdout.write("\rPercent: [{0}] {1}%".format(hashes + spaces, int(round(percent * 100))))
sys.stdout.flush()
应该产生如下所示的结果:
Percent: [############## ] 69%
... 括号保持不变,只有哈希值增加。
作为装饰器,这可能会更好。再等一天……
其他回答
http://code.activestate.com/recipes/168639-progress-bar-class/ (2002) http://code.activestate.com/recipes/299207-console-text-progress-indicator-class/ (2004) http://pypi.python.org/pypi/progressbar (2006)
还有很多教程等着你去谷歌。
一个非常简单的解决方案是将以下代码放入循环中:
把这个放在你的文件的主体(即顶部):
import sys
把这个放在你的循环体中:
sys.stdout.write("-") # prints a dash for each iteration of loop
sys.stdout.flush() # ensures bar is displayed incrementally
import time,sys
for i in range(100+1):
time.sleep(0.1)
sys.stdout.write(('='*i)+(''*(100-i))+("\r [ %d"%i+"% ] "))
sys.stdout.flush()
输出
[29 percent] ===================
下面是一个用Python编写的进度条的好例子:http://nadiana.com/animated-terminal-progress-bar-in-python
但如果你想自己写。你可以使用curses模块让事情变得更简单:)
(编辑) 也许更容易不是诅咒这个词。但是如果你想创建一个成熟的cui,那么curses会为你照顾很多东西。
(编辑) 由于旧的链接已经失效,我已经发布了我自己的Python Progressbar版本,请在这里获取:https://github.com/WoLpH/python-progressbar
我推荐使用tqdm - https://pypi.python.org/pypi/tqdm -它可以简单地将任何可迭代对象或进程转换为进度条,并处理所需终端的所有混乱。
从文档中可以看到:“tqdm可以很容易地支持回调/钩子和手动更新。这里有一个urllib的例子。”
import urllib
from tqdm import tqdm
def my_hook(t):
"""
Wraps tqdm instance. Don't forget to close() or __exit__()
the tqdm instance once you're done with it (easiest using `with` syntax).
Example
-------
>>> with tqdm(...) as t:
... reporthook = my_hook(t)
... urllib.urlretrieve(..., reporthook=reporthook)
"""
last_b = [0]
def inner(b=1, bsize=1, tsize=None):
"""
b : int, optional
Number of blocks just transferred [default: 1].
bsize : int, optional
Size of each block (in tqdm units) [default: 1].
tsize : int, optional
Total size (in tqdm units). If [default: None] remains unchanged.
"""
if tsize is not None:
t.total = tsize
t.update((b - last_b[0]) * bsize)
last_b[0] = b
return inner
eg_link = 'http://www.doc.ic.ac.uk/~cod11/matryoshka.zip'
with tqdm(unit='B', unit_scale=True, miniters=1,
desc=eg_link.split('/')[-1]) as t: # all optional kwargs
urllib.urlretrieve(eg_link, filename='/dev/null',
reporthook=my_hook(t), data=None)