进度条在Python中工作不正常。

huangapple go评论62阅读模式
英文:

Progress bar is not working good in python

问题

我正在尝试在Python中删除文件时创建一个进度条。这个Python脚本会打印目录中文件的计数,然后在删除文件时显示一个进度条。当删除10或11个文件时,它工作得很好。但是当文件数量更大,比如20时,它会显示这样的信息:

Found 20 files.
Deleting[########################################################################################################
.........Deleting[###############################################################################################
##################Deleting[######################################################################################
###########################Deleting[#############################################################################
####################################Deleting[####################################################################
#############################################Deleting[###########################################################
######################################################Deleting[##################################################
#################################################################################################################
###############################################]100.0%

但我想要打印成这样:

Found 20 files.
Deleting[####################.............]75%

这是我的代码:

import os
import sys
import time

out = sys.stdout

path_ = input("Enter the path: ")
count_ = 0
files = []
for path in os.listdir(path_):
    if os.path.isfile(os.path.join(path_, path)):
        count_ += 1
        files.append(path)

print(f"Found {count_} files.")
hashes = ""
count = 0
hash = 0
spaces = ".." * 20
for item in files:
    item = path_ + "\\" + item
    os.remove(item)
    count += 1
    per = count/count_ * 100
    for i in range(int(per)):
        hash += 1
        if hash == 10:
            hash = 0
            spaces = ".." * (count_ - count)
            hashes += "##"
    print("{}[{}{}]{}{}".format("Deleting", hashes, spaces, per, "%"), end='\r', file=out, flush=True)
    time.sleep(1)

print("\n")

这里我做错了什么?请帮忙。

英文:

I'm trying to make a progress bar when deleting files in python. This python script print the count of the files in a directory and then it will delete them while showing a progress bar. When deleting 10 or 11 files it is working good. But when the file count is larger like
20, It is showing this mess,

Found 20 files.
Deleting[########################################################################################################
.........Deleting[###############################################################################################
##################Deleting[######################################################################################
###########################Deleting[#############################################################################
####################################Deleting[####################################################################
#############################################Deleting[###########################################################
######################################################Deleting[##################################################
#################################################################################################################
###############################################]100.0%

But I want to print it like this,

Found 20 files.
Deleting[####################.............]75%

Here is my code ,

import os
import sys
import time

out = sys.stdout

path_ = input("Enter the path: ")
count_ = 0
files = []
for path in os.listdir(path_):
    if os.path.isfile(os.path.join(path_, path)):
        count_ += 1
        files.append(path)

print(f"Found {count_} files.")
hashes = ""
count = 0
hash = 0
spaces = ".." * 20
for item in files:
    item = path_ + "\\" + item
    os.remove(item)
    count += 1
    per = count/count_ * 100
    for i in range(int(per)):
        hash += 1
        if hash == 10:
            hash = 0
            spaces = ".." * (count_ - count)
            hashes += "##"
    print("{}[{}{}]{}{}".format("Deleting", hashes, spaces, per, "%"), end='\r', file=out, flush=True)
    time.sleep(1)

print("\n")

What am I doing wrong here? please help.

答案1

得分: 1

如果您不想使用 tqdm,这里是一个使用 f-strings 的示例。字符串的部分 :-<{BAR_LEN} 表示“填充字符串的其余部分,直到 BAR_LEN 个字符(在本例中为 20 个字符),使用 '-' 填充”。

from time import sleep

iterable = range(101)  # 这是您要循环的可迭代对象
count = len(iterable) - 1
BAR_LEN = 20  # 这是您的进度条的长度

for n in iterable:
    # 打印进度条
    # "#" 是您的填充字符,'-' 是空白部分
    print(
        '\r',
        f'Deleting[{"#" * round(n / (count / BAR_LEN)):-<{BAR_LEN}}]',  # 进度条
        f'{(n * 100) // count}%',  # 百分比
        end='', 
        flush=True,
    )
    sleep(0.2)  # 可选 - 模拟后台发生的一些操作

请注意,这只是代码的一部分,我没有回答您的问题,只提供了代码的翻译。

英文:

If you'd prefer not to use tqdm, here's an example using f-strings. The :-&lt;{BAR_LEN} part of the string means "fill the rest of the string, up to BAR_LEN characters (in this case, 20), with -"

from time import sleep


iterable = range(101)  # this is the iterable you want to loop over
count = len(iterable) - 1
BAR_LEN = 20  # this is the length of your progress bar

for n in iterable:
    # print the progress bar
    # &quot;#&quot; is your fill character, &#39;-&#39; is your empty segment
    print(
        &#39;\r&#39;,
        f&#39;Deleting[{&quot;#&quot; * round(n / (count / BAR_LEN)):-&lt;{BAR_LEN}}]&#39;  # bar
        f&#39;{(n * 100) // count}%&#39;,  # percentage
        end=&#39;&#39;, 
        flush=True,
    )
    sleep(0.2)  # optional - just simulates something happening in the background

答案2

得分: 1

我找到了适合我的东西,希望注释能让它易于理解。
这个解决方案不使用 os.system 来清除打印的行,所以应该适用于你的 IDE。

但我强烈建议研究 tqdm,因为它非常易于使用和优化,特别适合这种情况。

如有需要,请随时提出更多问题。不要忘记接受答案,如果它解决了你的问题!

英文:

I found something that works for me , hope the comments make it understandable.
This solution doesn't use os.system to clear the printed lines so it should work in your IDE.

Still, I strongly suggest looking into tqdm as it's very easy to use and optimized. for this kind of things.

Feel free to ask further questions if needed. Don't forget to accept an answer if it solved your issue !

import os
import sys
import time

out = sys.stdout

path_ = input(&quot;Enter the path: &quot;)
count_ = 0
files = []
for path in os.listdir(path_):
	if os.path.isfile(os.path.join(path_, path)):
		count_ += 1
		files.append(path)

print(f&quot;Found {count_} files.&quot;)
count = 0
hash_counter = 0
	#avoid creating a variable named &#39;hash&#39;, as it is a method name.
spaces = &quot;..&quot; * 20
for item in files:
	item = path_ + &quot;\\&quot; + item
	os.remove(item)
	count += 1
	per = count/count_ * 100
	is_last_file = (count==count_)
		#this variable checks if the number of deleted files (count) si equal to the total number of files (count_),
		#so it will return True only when we&#39;re deleting the last file of the directory.
	for i in range(int(per)):
		hash += 1
		if hash == 10:
			hash = 0
			number_of_hashes = int(round(per/5, 0))
				#first we calculate the number of hashes (&quot;##&quot;) in our progress bar.
				#we divide the percentage by five because we have a percentage x/100 but we want to display it on a divider of 20 (x/20),
				#so we divide your percentage by 5 (e.g 40% of 20 = 5 hashes)
			hashes = &quot;##&quot; * number_of_hashes
			spaces = &quot;..&quot; * (20-number_of_hashes)
				#we calculate easily the number of spaces : it&#39;s 20 (the size of our progress bar) minus the number of hashes.
	print(f&quot;{&#39;Deleting&#39; if not is_last_file else &#39;Deleted&#39;} [{hashes}{spaces}] {per:.1f}%&quot;, end=(&#39;\r&#39; if not is_last_file else &#39;\n&#39;), file=out, flush=True)
		#using f-strings here is more pythonic ! ;)
		#Also as you can see i used &quot;:.1f&quot; after the percentage. this way we have only one decimal after our float.
	time.sleep(1)
		#you can remove this from your code afterwards.

print(&quot;\n&quot;)

答案3

得分: 0

主要问题在于你的内部循环中。

首先,因为你没有重置hashes,所以它会多计算所需数量的哈希值。例如,在10%时,它会添加两个哈希值,然后在20%时,它会同时计算10%和20%,并额外添加四个哈希值,总共达到六个哈希值。我不认为这是你的意图。

其次,我认为hash也不会按照你的期望计数。例如,当从20个文件中删除一个文件(5%)时,哈希值变为5。然后在第二个文件删除(10%)时,哈希值从5开始递增,并在中途重置,最终停在5。

英文:

The main issue is in your inner for loop.

First, because you don't reset hashes, it over counts the necessary number of hashes. E.g. at 10%, it adds two hashes and then at 20% it counts both 10% and 20% and adds four additional hashes for a total of six hashes. I don't believe you intend this.

Second, I don't think the hash is counting as you desire either. For example, at one file removed out of 20 (5%), hash goes to 5. Then at the second file removed (10%), hash resumes incrementing from 5 and resets midway and ends at 5.

答案4

得分: 0

"hash" 是一个关键字,不要重新赋值它。你的代码非常低效和不优雅。

我已经重构了你的代码。

import os
from collections import deque

def cyan(text):
    return f'\x1b[36m{text}\x1b[0m'

def recur_dir(folder, path):
    files = deque()
    for entry in os.scandir(folder):
        if entry.is_file():
            files.append(f'{path}/{entry.name}')
        elif entry.is_dir():
            files.extend(recur_dir(entry, f'{path}/{entry.name}'))
    return files

def delete(folder):
    files = recur_dir(folder, folder)
    total = len(files)
    for i, file in enumerate(files, start=1):
        os.remove(file)
        progress = i/total*100
        print(f"\rDeleting[{cyan('█' * round(progress)):·<109}] {progress:.2f}%", end='', flush=True)

使用方法:delete('path/to/folder')

进度条:

Deleting[██████████████████████████████████████████████████████████████·······················································] 61.97%

带有颜色:

进度条在Python中工作不正常。

进度条在Python中工作不正常。

请注意,文件夹路径不能以 / 结尾。

要获取所有文件,你可以使用一个简单的递归函数。你的代码不会递归列出给定文件夹下的所有文件,这意味着它不会删除给定文件夹的子目录中的文件。

我的代码会递归列出给定文件夹下的所有文件。

要获取集合中元素的数量,只需使用 len(lst)。你不需要手动重复递增一个变量。

然后,你可以使用 enumerate 来计算进度,进度只是总数除以索引(如果使用基于 1 的索引)。就是这么简单。


更新

那个魔法数字需要是 109,而不是 100,因为在着色文本之后,字符串将包含 ANSI 代码,ANSI 代码不会被打印出来,而是改变文本的颜色,但在计算长度时仍然会计为字符,并占据了额外的 9 个字符。

小于符号表示字符串应该左对齐,因为有 9 个额外字符,所以进度条只有在进度达到 91% 时才会是 91 个字符长,因为你只需要在 100 个字符左侧填充 91 个字符。因此,使用 109 将使进度条始终为 100 个字符长。

英文:

hash is a keyword and don't reassign it. Your code is very inefficient and inelegant.

I have refactored your code.

import os
from collections import deque

def cyan(text):
    return f&#39;\x1b[36m{text}\x1b[0m&#39;

def recur_dir(folder, path):
    files = deque()
    for entry in os.scandir(folder):
        if entry.is_file():
            files.append(f&#39;{path}/{entry.name}&#39;)
        elif entry.is_dir():
            files.extend(recur_dir(entry, f&#39;{path}/{entry.name}&#39;))
    return files

def delete(folder):
    files = recur_dir(folder, folder)
    total = len(files)
    for i, file in enumerate(files, start=1):
        os.remove(file)
        progress = i/total*100
        print(f&quot;\rDeleting[{cyan(&#39;█&#39; * round(progress)):&#183;&lt;109}] {progress:.2f}%&quot;, end=&#39;&#39;, flush=True)

Use like this: delete(&#39;path/to/folder&#39;).

Progress bar:

Deleting[██████████████████████████████████████████████████████████████&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;] 61.97%

With color:

进度条在Python中工作不正常。

进度条在Python中工作不正常。

Note that the folder path cannot end with &#39;/&#39;.

To get all files you can use a simple recursive function. Your code doesn't list all files under the given directory recursively, meaning it won't delete files inside the subdirectories of the given folder.

My code lists all files inside the given directory recursively.

To get the count of elements inside a collection just use len(lst). You don't have to repeated increment a variable manually.

Then you can use enumerate to calculate progress, the progress is simply the total divided by index (if you use one-based indexing). It is that simple.


Update

That magic number needs to be 109, not 100, because after coloring the text, the string will contain ANSI codes, the ANSI codes won't be printed, instead they change the color of the text, but they will still be counted as characters when calculating length, and they account for 9 extra characters.

The less than sign indicates the string should be left justified, since there are 9 extra characters, the progress bar will only be 91 characters long until the progress is 91%, because you only need 91 characters to left pad to 100 characters. So using 109 will make the progress bar always 100 characters long.

答案5

得分: 0

使用 f-string 格式。它会更快地删除。它可以删除超过20个文件。

将第31行的内容更改为:

print(f"Deleting {hashes} {spaces}, {per}% \r", file=out, flush=True)

输出:

找到10个文件。
删除 ## .................., 10.0% 

删除 ###### ................, 20.0% 

删除 ############ .............., 30.0% 

删除 #################### ............, 40.0% 

删除 ############################## .........., 50.0% 

删除 ########################################## ........, 60.0% 

删除 ######################################################## ......, 70.0% 

删除 ######################################################################## ...., 80.0% 

删除 ########################################################################################## .., 90.0% 

删除 ############################################################################################################## , 100.0% 

另外,这是删除冗余的部分:

print(f"Deleting {spaces} {per}% \r", file=out, flush=True)

输出:

找到20个文件。
删除 ........................................ 5.0% 

删除 .................................... 10.0% 

删除 .................................. 15.0% 

删除 ................................ 20.0% 

删除 .............................. 25.0% 

删除 ............................ 30.0% 

删除 .......................... 35.0% 

删除 ........................ 40.0% 

删除 ...................... 45.0% 

删除 .................... 50.0% 

删除 .................. 55.00000000000001% 

删除 ................ 60.0% 

删除 .............. 65.0% 

删除 ............ 70.0% 

删除 .......... 75.0% 

删除 ........ 80.0% 

删除 ...... 85.0% 

删除 .... 90.0% 

删除 .. 95.0% 

删除  100.0% 
英文:

Using the f-string format. It will delete faster. It can delete more than 20 files.

Change this on line 31:
print(&quot;{}[{}{}]{}{}&quot;.format(&quot;Deleting&quot;, hashes, spaces, per, &quot;%&quot;), end=&#39;\r&#39;, file=out, flush=True)

to:

print(f&quot;Deleting {hashes} {spaces}, {per}% \r&quot;, file=out, flush=True)

Output:
Found 10 files.
Deleting ## .................., 10.0%

Deleting ###### ................, 20.0% 

Deleting ############ .............., 30.0% 

Deleting #################### ............, 40.0% 

Deleting ############################## .........., 50.0% 

Deleting ########################################## ........, 60.0% 

Deleting ######################################################## ......, 70.0% 

Deleting ######################################################################## ...., 80.0% 

Deleting ########################################################################################## .., 90.0% 

Deleting ############################################################################################################## , 100.0% 

Another this is removing harsh.

print(f&quot;Deleting {spaces} {per}% \r&quot;, file=out, flush=True)

Output:

Found 20 files.
Deleting ........................................ 5.0% 

Deleting .................................... 10.0% 

Deleting .................................. 15.0% 

Deleting ................................ 20.0% 

Deleting .............................. 25.0% 

Deleting ............................ 30.0% 

Deleting .......................... 35.0% 

Deleting ........................ 40.0% 

Deleting ...................... 45.0% 

Deleting .................... 50.0% 

Deleting .................. 55.00000000000001% 

Deleting ................ 60.0% 

Deleting .............. 65.0% 

Deleting ............ 70.0% 

Deleting .......... 75.0% 

Deleting ........ 80.0% 

Deleting ...... 85.0% 

Deleting .... 90.0% 

Deleting .. 95.0% 

Deleting  100.0% 

huangapple
  • 本文由 发表于 2023年6月5日 21:40:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/76407016.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定