python - 在 Python 中使用递归进行高效的驱动器扫描
问题描述
原始问题:
我正在尝试递归扫描目录,以便使用下面的代码获取磁盘的占用大小以及每个文件和文件夹的详细信息。下面的代码运行良好,但我需要一些关于提高效率的建议,以便扫描占用空间/数据为 200 GB 或更多的驱动器。5.49 GB(244,169 个文件和 34,253 个文件夹)占用空间的磁盘的测试结果如下:
- 如果代码在没有列表追加操作的情况下运行,则扫描磁盘大约需要 8 分钟,效率不高
- 如果我包含 list append 语句,情况会变得更糟,然后大约需要 25 分钟 --> 瓶颈
import os
import sys
import logging
from os.path import *
def scanSlot(path):
"""Return total size of files in given path and subdirs."""
global dir_list
global path_list
try:
dir_list = os.scandir(path)
except Exception as e:
logging.info(">>> Access Denied for " + path)
dir_list = {}
tot_size = 0
for file in dir_list:
file_stat = file.stat()
time_stat = os.stat(file.path)
# If the given file object is a directory recursively call the function again
if file.is_dir(follow_symlinks=False):
#Recursive Call
bytes = scanSlot(file.path)
#Calculating Size
tot_size += bytes
# logging.info('Dirname:'+str(file)+' Path'+str(file.path) +' Size'+str(bytes))
# List Append
path_list.append((file.name,file.path,file_stat.st_mode,file_stat.st_ino,file_stat.st_dev,file_stat.st_nlink,file_stat.st_uid,file_stat.st_gid,tot_size,
datetime.fromtimestamp(time_stat.st_atime),datetime.fromtimestamp(time_stat.st_mtime),datetime.fromtimestamp(time_stat.st_ctime),"dir"))
# If the given file object is a file then retrieve all the details
if file.is_file(follow_symlinks=False):
# logging.info('Filename:'+str(file)+ ' Path'+str(file.path) +' Size'+str(time_stat))
tot_size += file.stat(follow_symlinks=False).st_size
# List Append
path_list.append((file.name,file.path,file_stat.st_mode,file_stat.st_ino,file_stat.st_dev,file_stat.st_nlink,file_stat.st_uid,file_stat.st_gid,file_stat.st_size,
datetime.fromtimestamp(time_stat.st_atime),datetime.fromtimestamp(time_stat.st_mtime),datetime.fromtimestamp(time_stat.st_ctime),"file"))
return tot_size
上述代码的函数调用:
server_size = scanSlot('D:\\New folder')
我尝试使用以下方法优化代码:
列表追加操作不容忽视,因为进一步分析需要该路径列表中的详细信息。
更新:
根据@triplee的建议并在此处的实现的帮助下,我已经使用 os.walk() 实现了目录扫描,显然它的速度更快(19.6GB,2,75,559 个文件,38,592 个文件夹在执行 I/O 时在 20 分钟内扫描到每个文件目录的日志文件)。代码如下:
仅供参考:仍在测试
def scanSlot(path):
total_size = 0
global path_list
for dirpath, dirnames, filenames in os.walk(path):
for f in filenames:
fp = os.path.join(dirpath, f)
# skip if it is symbolic link
if not os.path.islink(fp):
# logging.info('Filename:'+str(fp)+'Size:'+str(os.path.getsize(fp)))
file_stat = os.stat(fp)
path_list.append((f,fp,file_stat.st_mode,file_stat.st_ino,file_stat.st_dev,file_stat.st_nlink,file_stat.st_uid,file_stat.st_gid,os.path.getsize(fp),
datetime.fromtimestamp(file_stat.st_atime),datetime.fromtimestamp(file_stat.st_mtime),datetime.fromtimestamp(file_stat.st_ctime),"file"))
total_size += os.path.getsize(fp)
return total_size
if __name__ == "__main__":
logging.info('>>> Start:' + str(datetime.now().time()))
# So basically run os.walk() for a drive and then do so for all directories present in it
for dirpath, dirnames, filenames in os.walk('F:\\'):
for f in dirnames:
fp = os.path.join(dirpath, f)
dir_size = scanSlot(fp)
file_stat = os.stat(fp)
logging.info('Dirname:'+str(fp)+'Size:'+str(dir_size))
path_list.append((f,fp,file_stat.st_mode,file_stat.st_ino,file_stat.st_dev,file_stat.st_nlink,file_stat.st_uid,dir_size,
datetime.fromtimestamp(file_stat.st_atime),datetime.fromtimestamp(file_stat.st_mtime),datetime.fromtimestamp(file_stat.st_ctime),"dir"))
logging.info('>>> End:' + str(datetime.now().time()))
进一步的问题:
- 如何使它更高效/更快,最初我认为多处理是在 3 个不同进程下并行运行对 3 个驱动器的扫描。
参考:
follow_symlinks的解释也可以在上面的参考链接中找到。
解决方案
推荐阅读
- javascript - 在单个弹出页面中打开带有日期和时间的按钮单击模式?HTML 和 JavaScript
- c# - 通过带有数字证书的 WCF 使用 Web 服务
- excel - 有没有办法匹配excel中的列?没有行名
- python - Cythonclosure_freelist_size 选项
- ios - 使用 Swift 在 Xcode 中拉动 tableView 以刷新时活动指示器不旋转
- python - 为什么我的轮廓没有闭合(Python、OpenCV)?
- python - 以某种自定义方式使用 concurrent.futures 时无法打印函数的结果
- google-apps-script - 具有时间驱动重置功能的 Google 电子表格复选框为其他列增加了价值
- swift - 需要公共初始化?(编码器aDecoder:NSCoder){fatalError(“初始化(编码器:)尚未实现”)}
- dependency-injection - 为什么 MassTransit `ServiceCollectionBusConfigurator` 不通过`AddConsumer` 将`IConsumer` 添加到`DI`?