【问题标题】:Most efficient way to traverse file structure Python遍历文件结构Python的最有效方法
【发布时间】:2012-09-12 06:50:35
【问题描述】:

是否以以下最耗时的方式使用 os.walk 递归搜索文件夹并返回所有以 .tnt 结尾的文件?

for root, dirs, files in os.walk('C:\\data'):
    print "Now in root %s" %root
    for f in files:
        if f.endswith('.tnt'):

【问题讨论】:

  • 我想你可以从中做出一个列表理解,这可能会稍微快一些,而且打字也会稍微少一些。不要忘记聪明人曾经说过的话:"Premature Optimization is the root of all evil".
  • 使用os.walk 是一个好方法。这是最好的方式吗?我不知道。但我和Voltaire 合作。
  • 为什么列表理解会更快?这将涉及实际生成一个列表,而不是使用这个 os.walk 生成器...
  • @nneonneo:好的,点了——然后是生成器表达式。
  • 它不是过早的优化。我只是希望有办法在任何时候刮胡子

标签: python optimization directory subdirectory


【解决方案1】:

是的,使用os.walk 确实是最好的方法。

【讨论】:

  • os.scandir() 怎么样?
  • @denfromufa: os.scandir() 是在 Python 3.5 中添加的(long 在此答案发布后)。 os.walk() 被改造成使用 os.scandir(),所以 os.walk()仍然是递归扫描目录的最有效方式。
  • 重点是python 2.7可以安装作者提供的pypi包scandir!它将我的网络目录扫描速度从 18 秒缩短到 6 秒!
  • 啊,当然,但是你没有提到你安装了一个外部包!然后我会复制 Python 3.5 os.walk() implementation 并使用它而不是 2.7 os.walk() 函数。
  • @denfromufa:更好!
【解决方案2】:

正如大家所说,os.walk 几乎可以肯定是最好的方法。

如果您确实遇到了性能问题,并且分析表明它是由 os.walk(和/或使用 .endswith 迭代结果)引起的,那么您最好的答案可能是跳出 Python。将上面的所有代码替换为:

for f in sys.argv[1:]:

现在您需要一些外部工具来收集路径并运行您的脚本。 (理想情况下,将尽可能多的路径批处理到每个脚本执行中。)

如果您可以依靠 Windows 桌面搜索对驱动器进行索引,它应该只需要进行快速数据库操作即可找到特定路径下具有特定扩展名的所有文件。我不知道如何编写一个批处理文件来运行该查询并将结果作为参数列表传递给 Python 脚本(或运行查询并将结果传递给 IronPython 而不将其序列化为列表的 PowerShell 文件论点),但值得先研究一下。

如果您不能依赖平台的桌面搜索索引,那么在任何 POSIX 平台上,使用这个单行 shell 脚本几乎肯定是最快和最简单的:

find /my/path -name '*.tnt' -exec myscript.py {} +

不幸的是,您不是在 POSIX 平台上,而是在 Windows 上,它不附带 find 工具,这是在这里完成所有繁重工作的东西。

有本地 Windows 的 find 端口,但您必须弄清楚命令行的复杂性才能正确引用所有内容并格式化路径等,这样您就可以编写单行批处理文件。或者,您可以安装 cygwin 并使用您在 POSIX 系统上使用的完全相同的 shell 脚本。或者您可以找到一个更符合 Windows 的工具来满足您的需求。

可以想象,这可能会更慢而不是更快 - Windows 并非旨在以尽可能少的开销执行大量小进程,而且我相信它对命令行的限制比 linux 或 OS X 等平台更小,所以你等待解释器启动和退出的时间可能比您节省的时间长。你必须测试才能看到。事实上,您可能希望同时测试本机和 cygwin 版本(在后一种情况下,使用本机和 cygwin Python)。

您实际上find 调用移动到批处理/shell 脚本中;这可能是最简单的答案,但还有其他答案,例如使用 subprocess 从 Python 中调用 find。这可能会解决由于启动解释器次数过多而导致的性能问题。

获得适量的并行性也可能会有所帮助——将脚本的每次调用分拆到后台,不要等待它们完成。 (我相信在 Windows 上,shell 不参与其中;取而代之的是一个名为“run”之类的工具,它启动了一个与 shell 分离的进程。但我不记得细节了。)

如果这些都不起作用,您可能必须编写一个自定义 C 扩展,以实现最快的 Win32 或 .NET 功能(这也意味着您必须进行研究以找出它是什么……),这样您就可以在 Python 中调用它。

【讨论】:

    猜你喜欢
    • 2020-10-18
    • 1970-01-01
    • 1970-01-01
    • 2017-02-03
    • 1970-01-01
    • 2011-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多