如何有效地计算给定目录中每个子文件夹和文件的大小?
到目前为止我所拥有的代码做了我想要的事情,但由于我必须如何计算父文件夹大小,它效率低下,速度缓慢。
以下是我目前的时间安排:
Section 1: 0.53 s
Section 2: 30.71 s
代码:
import os
import time
import collections
def folder_size(directory):
parents = []
file_size = collections.defaultdict(int)
parent_size = collections.defaultdict(int)
t0 = time.time()
#### Section 1 ####
for root, dirs, files in os.walk(directory):
root = os.path.abspath(root)
parents.append(root)
for f in files:
f = os.path.join(root, f)
file_size[f] += os.path.getsize(f)
###################
t1 = time.time()
print(f'walk time: {round(t1-t0, 2)}')
#### Section 2 ####
for parent in parents:
parent_split = parent.split(os.sep)
for filename, value in file_size.items():
parent_for_file = filename.split(os.sep)[:len(parent_split)]
if parent_split == parent_for_file:
parent_size[parent] += value
###################
t2 = time.time()
print(f'parent size time: {round(t2-t1, 2)}')
return file_size, parent_size
代码的第2部分效率低下,原因如下:
效率低下#1
我需要捕获没有文件的文件夹。例如,在这样的文件夹结构中:
TopFolder
├── FolderA
│ ├── folder_P1
│ │ ├── folder_P1__file_1.txt
│ │ └── folder_P1__file_2.txt
│ ├── folder_P10
│ │ ├── folder_P10__file_1.txt
│ │ └── folder_P10__file_2.txt
.
.
.
我希望最后得到每个目录的大小(以字节为单位),如下所示:
'..../TopFolder': 114000,
'..../TopFolder/FolderA': 38000,
'..../TopFolder/FolderA/folder_P1': 38,
'..../TopFolder/FolderA/folder_P10': 38,
.
.
.
为了获得包含子文件夹(如TopFolder
和FolderA
)的文件夹的总大小,我将父文件夹分开存储,这样我就可以返回并根据文件大小计算它们的大小。
效率低下#2
这段代码非常慢,因为我必须对字符串进行split()
运算来确定父文件夹(通过cProfile
模块确认)。我必须这样做是因为如果我执行类似下面的代码片段的操作,某些文件夹的大小将无法正确计算。我也尝试过使用re.split()
,但速度更慢。
#### Section 2 ####
...
for parent in parents:
for filename, value in file_size.items():
if parent in filename:
parent_size[parent] += value
...
###################
下面是if parent in filename
的错误输出:
'..../TopFolder': 114000,
'..../TopFolder/FolderA': 38000,
'..../TopFolder/FolderA/folder_P1': 4256,
'..../TopFolder/FolderA/folder_P10': 456,
'..../TopFolder/FolderA/folder_P100': 76,
'..../TopFolder/FolderA/folder_P1000': 38,
.
.
.
下面是原始代码的正确输出:
'..../TopFolder': 114000,
'..../TopFolder/FolderA': 38000,
'..../TopFolder/FolderA/folder_P1': 38,
'..../TopFolder/FolderA/folder_P10': 38,
'..../TopFolder/FolderA/folder_P100': 38,
'..../TopFolder/FolderA/folder_P1000': 38,
.
.
.
第2节要么需要改进,使其运行得更快,要么需要将第2节合并到第1节中。我在互联网上搜索了一些想法,但只能找到有关计算顶级目录大小的信息,而且没有什么想法。
下面是我用来创建示例目录结构的代码:
import os
folder = 'TopFolder'
subfolders = ['FolderA', 'FolderB', 'FolderC']
for i in range(1000):
for subfolder in subfolders:
path = os.path.join(folder, subfolder, f'folder_P{i + 1}')
if not os.path.isdir(path):
os.makedirs(path)
for k in range(2):
with open(os.path.join(path, f'folder_P{i + 1}__file_{k + 1}.txt'), 'w') as file_out:
file_out.write(f'Hello from file {k + 1}!\n')```
1条答案
按热度按时间jjhzyzn01#
使用
os.walk
时,您不必使用os.scandir
生成的文件条目对象,os.walk
会在内部调用这些对象。因此,您可以使用每个文件条目的stat
对象,而不必为每个文件使用os.path.getsize
进行单独的系统调用。您也不应该仅仅为了查找父目录名而解析路径,因为在列出具有该名称的目录时,您已经有了父目录名。以下示例仅用0.2秒就可以为www.example.com上的测试目录结构生成所需的输出repl.it:
演示:https://replit.com/@blhsing/SparseStainedNature