【问题标题】:Output in stdout differs in cmd and Python consolestdout 中的输出在 cmd 和 Python 控制台中不同
【发布时间】:2023-12-19 10:09:01
【问题描述】:

我是 Python 新手,正在开发一个小程序,该程序将给定扩展名的所有文件从文件夹及其子文件夹复制到另一个目录。最近我添加了一个简单的进度条和剩余文件的计数器。 问题是,当我从 cmd 运行它并且计数器来自 1000 到 999 时,cmd 会在最后一位而不是空格处添加一个零。此外,当程序完成时,剩余文件计数器应替换为“完成”一词。而且效果也不好。

我尝试将sys.stdout.write替换为print并尝试不使用f-strings,结果是一样的。

def show_progress_bar(total, counter=0, length=80):
    percent = round(100 * (counter / total))
    filled_length = int(length * counter // total)
    bar = '=' * filled_length + '-' * (length - filled_length)
    if counter < total:
        suffix = f'Files left: {total - counter}'
    else:
        suffix = 'Done.'
    sys.stdout.write(f'\rProgress: |{bar}| {percent}% {suffix}')
    sys.stdout.flush()

def selective_copy(source, destination, extension):
    global counter
    show_progress_bar(total)
    for foldername, subfolders, filenames in os.walk(source):
        for filename in filenames:
            if filename.endswith(extension):
                if not os.path.exists(os.path.join(destination, filename)):
                    shutil.copy(os.path.join(foldername, filename), os.path.join(destination, filename))
                else:
                    new_filename = f'{os.path.basename(foldername)}_{filename}'
                    shutil.copy(os.path.join(foldername, filename), os.path.join(destination, new_filename))
                counter += 1
                show_progress_bar(total, counter)

我希望 cmd 中的输出与控制台中的输出相同,即: 程序运行:

Progress: |=========-----------------------------------------------------------------------| 12% Files left: 976

程序完成:

Progress: |================================================================================| 100% Done.

但是在 cmd 中我得到了这个: 程序运行:

Progress: |=========-----------------------------------------------------------------------| 12% Files left: 9760

程序完成:

Progress: |================================================================================| 100% Done. left: 100

【问题讨论】:

  • 您需要“清理”该行的其余部分。查看此示例解决方案*.com/a/3419991/6018688。您的问题是,您的字符数未知,因为文件总文件数可能会发生变化。因此,您需要通过允许最大预期计数或提前计算进度行的最大长度来清理整个行的其余部分来考虑更改文件编号。此外,无需使用 sys - 使用 print("foo", end="\r", flush=True)
  • @f*egli,感谢您的建议!不知道可以在打印中使用冲洗。

标签: python python-3.x cmd console ipython


【解决方案1】:

通常,打印“\r”会将光标返回到行首,但不会删除任何已写入的内容。所以如果你写“1000”后跟“\r”后跟“999”,“1000”的最后一个0仍然可见。

(我不确定为什么在您的 Python 控制台中没有发生这种情况。也许它以不同的方式解释“\r”。如果不确切知道您正在运行什么软件,很难说。)

一种解决方案是在输出后打印几个空格,以确保覆盖稍长的旧消息。您可能只需为“剩余文件:”后缀留一个空格,因为它最多只减少一个字符,但“完成”后缀需要更多。

if counter < total:
    suffix = f'Files left: {total - counter} '
else:
    suffix = 'Done.               '

【讨论】:

  • 谢谢你,@Kevin!我最终将您的建议和上面的@f*egli 的建议结合起来,现在效果很好。