gpt4 book ai didi

Python 2 vs. 3 慢 os.path.getmtime() 与巨大的文件列表 - 为什么?

转载 作者:行者123 更新时间:2023-11-28 17:00:36 25 4
gpt4 key购买 nike

我目前成功地使用了一个 python 2.7 脚本,它在一个巨大的目录/文件路径上递归循环,收集所有文件的路径,获取这些文件的 mtime 以及具有相同路径和名称的各个文件的 mtime,但作为比较的pdf文件。我在 python 2.7 脚本中使用 scandir.walk() ,在 python 3.7 中使用 os.walk() ,最近更新为也使用 scandir 算法(没有额外的 stat() 调用)。

但是,脚本的 python 3 版本仍然明显较慢!这不是由于算法的 scandir/walk 部分,但显然是由于 getmtime 算法(然而,它在 python2 和 3 中是相同的调用)或巨大列表的处理(我们正在谈论 ~此列表中有 500.000 个条目)。

知道可能导致此问题的原因以及如何解决此问题吗?

#!/usr/bin/env python3
#
# Imports
#
import sys
import time
from datetime import datetime
import os
import re

#
# MAIN THREAD
#

if __name__ == '__main__':

source_dir = '/path_to_data/'

# Get file list
files_list = []
for root, directories, filenames in os.walk(source_dir):
# Filter for extension
for filename in filenames:
if (filename.lower().endswith(('.msg', '.doc', '.docx', '.xls', '.xlsx'))) and (not filename.lower().startswith('~')):
files_list.append(os.path.join(root, filename))

# Sort list
files_list.sort(reverse=True)

# For each file, the printing routine is performed (including necessity check)
all_documents_counter = len(files_list)
for docfile_abs in files_list:

print('\n' + docfile_abs)

# Define files
filepathname_abs, file_extension = os.path.splitext(docfile_abs)
filepath_abs, filename = os.path.split(filepathname_abs)

# If the filename does not have the format # # # # # # # *.xxx (e.g. seven numbers), then it is checked whether it is referenced in the databse. If not, it is moved to a certain directory
if (re.match(r'[0-9][0-9][0-9][0-9][0-9][0-9][0-9](([Aa][0-9][0-9]?)?|(_[0-9][0-9]?)?|([Aa][0-9][0-9]?_[0-9][0-9]?)?)\...?.?', filename + file_extension) is None):
if any(expression in docfile_abs for expression in ignore_subdirs):
pass
else:
print('Not in database')

# DOC
docfile_rel = docfile_abs.replace(source_dir, '')

# Check pdf
try:
pdf_file_abs = filepathname_abs + '.pdf'
pdf_file_timestamp = os.path.getmtime(pdf_file_abs)
check_pdf = True
except(FileNotFoundError):
check_pdf = False
# Check PDF
try:
PDF_file_abs = filepathname_abs + '.PDF'
PDF_file_timestamp = os.path.getmtime(PDF_file_abs)
check_PDF = True
except(FileNotFoundError):
check_PDF = False

# Check whether ther are lowercase or uppercase extension and decide what to do if there are none, just one or both present
if (check_pdf is True) and (check_PDF is False):
# Lower case case
pdf_extension = '.pdf'
pdffile_timestamp = pdf_file_timestamp
elif (check_pdf is False) and (check_PDF is True):
# Upper case case
pdf_extension = '.PDF'
pdffile_timestamp = PDF_file_timestamp
elif (check_pdf is False) and (check_PDF is False):
# None -> set timestampt to zero
pdf_extension = '.pdf'
pdffile_timestamp = 0
elif (check_pdf is True) and (check_PDF is True):
# Both are present, decide for the newest and move the other to a directory
if (pdf_file_timestamp < PDF_file_timestamp):
pdf_extension = '.PDF'
pdf_file_rel = pdf_file_abs.replace(source_dir, '')
pdffile_timestamp = PDF_file_timestamp
elif (PDF_file_timestamp < pdf_file_timestamp):
pdf_extension = '.pdf'
PDF_file_rel = PDF_file_abs.replace(source_dir, '')
pdffile_timestamp = pdf_file_timestamp

# Get timestamps of doc and pdf files
try:
docfile_timestamp = os.path.getmtime(docfile_abs)
except OSError:
docfile_timestamp = 0

# Enable this to force a certain period to be printed
DateBegin = time.mktime(time.strptime('01/02/2017', "%d/%m/%Y"))
DateEnd = time.mktime(time.strptime('01/03/2017', "%d/%m/%Y"))

# Compare stimestamps and print or not
if (pdffile_timestamp < docfile_timestamp) or (pdffile_timestamp == 0):

# Inform that there should be printed
print('\tPDF should be printe.')

else:
# Inform that there was no need to print
print('\tPDF is up to date.')


# Exit
sys.exit(0)

最佳答案

不确定是什么解释了差异,但即使 os.walk 已增强为使用 scandir,它也不会进一步扩展到 getmtime 调用,它再次访问文件属性。

最终目标是调用os.path.getmtime根本

os.walk 中的加速是关于不执行两次 stat 以了解对象是目录还是文件。但是内部 DirEntry 对象(scandir 产生)永远不会公开,因此您不能重用它来检查文件时间。

如果不需要回避,可以用os.scandir完成:

for dir_entry in os.scandir(r"D:\some_path"):
print(dir_entry.is_dir()) # test for directory
print(dir_entry.stat()) # returns stat object with date and all

循环内的那些调用是零成本完成的,因为 DirEntry 对象已经缓存了此信息。

因此,要保存 getmtime 调用,您必须递归地获取 DirEntry 对象。

这里没有本地方法,但是有 recipies,示例在这里:How do I use os.scandir() to return DirEntry objects recursively on a directory tree?

通过这样做,您的代码在 python 2 和 python 3 中会更快,因为每个对象只有 1 次 stat 调用,而不是 2 次。

编辑:在您编辑显示代码后,您似乎正在从其他条目构建 pdf 名称,因此您不能依赖 DirEntry 结构来获取时间,甚至不确定该文件存在(如果您使用的是 Windows,则无需测试 pdf 和 PDF,因为文件名不区分大小写)。

最好的策略是建立一个包含相关时间和所有文件的大数据库(使用字典)然后扫描它。我已经成功地使用这种方法在一个包含 3500 万个文件的慢速网络驱动器上找到旧/大文件。在我个人的例子中,扫描文件一次,并将结果转储到一个大的 csv 文件中(需要几个小时,对于 6Gb 的 csv 数据),然后进一步的后处理加载数据库并执行各种任务(更快,因为没有磁盘访问参与)

关于Python 2 vs. 3 慢 os.path.getmtime() 与巨大的文件列表 - 为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54829029/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com