从列表 os 文件路径 (Python) 构造树 - 取决于性能

Posted

技术标签:

【中文标题】从列表 os 文件路径 (Python) 构造树 - 取决于性能【英文标题】:Construct a tree from list os file paths (Python) - Performance dependent 【发布时间】:2011-12-13 05:55:55 【问题描述】:

嘿,我正在开发一个用 python 编写的高性能文件管理/分析工具包。 我想创建一个函数,给我一个树格式的列表或类似的东西。 类似question (java-related)

发件人:

dir/file
dir/dir2/file2
dir/file3
dir3/file4
dir3/file5

注意:路径列表未排序

收件人:

dir/
    file
    dir2/
        file2
    file3
dir3/
    file4
    file5

[[dir, [file, [dir2, [file2]], file3]], [dir3, [file4, file5]]]

类似的东西。我一直在尝试一些想法,但没有一个能提供我想要的速度。

注意:我已经有了路径列表,所以不用担心。该函数获取路径列表并给出树列表。

提前致谢

【问题讨论】:

« 我正在开发高性能文件管理/分析工具包用python编写。»。 ..哎哟! :( 哈哈,我知道,我想先实现一些合理的实现,然后我将使用 cython 等更底层的实现...... 【参考方案1】:

现在您已经进一步澄清了问题,我想以下是您想要的:

from collections import defaultdict

input_ = '''dir/file
dir/dir2/file2
dir/file3
dir2/alpha/beta/gamma/delta
dir2/alpha/beta/gamma/delta/
dir3/file4
dir3/file5'''

FILE_MARKER = '<files>'

def attach(branch, trunk):
    '''
    Insert a branch of directories on its trunk.
    '''
    parts = branch.split('/', 1)
    if len(parts) == 1:  # branch is a file
        trunk[FILE_MARKER].append(parts[0])
    else:
        node, others = parts
        if node not in trunk:
            trunk[node] = defaultdict(dict, ((FILE_MARKER, []),))
        attach(others, trunk[node])

def prettify(d, indent=0):
    '''
    Print the file tree structure with proper indentation.
    '''
    for key, value in d.iteritems():
        if key == FILE_MARKER:
            if value:
                print '  ' * indent + str(value)
        else:
            print '  ' * indent + str(key)
            if isinstance(value, dict):
                prettify(value, indent+1)
            else:
                print '  ' * (indent+1) + str(value)



main_dict = defaultdict(dict, ((FILE_MARKER, []),))
for line in input_.split('\n'):
    attach(line, main_dict)

prettify(main_dict)

它输出:

dir3
  ['file4', 'file5']
dir2
  alpha
    beta
      gamma
        ['delta']
        delta
          ['']
dir
  dir2
    ['file2']
  ['file', 'file3']

注意几点:

脚本大量使用defaultdicts,基本上这允许跳过检查是否存在密钥及其初始化(如果不存在) 目录名称映射到字典键,我认为这对您来说可能是一个很好的功能,因为键是散列的,您将能够比使用列表更快地检索信息。您可以以main_dict['dir2']['alpha']['beta']...的形式访问层次结构... 注意.../delta.../delta/ 之间的区别。我认为这有助于您快速区分叶子是目录还是文件。

我希望这能回答您的问题。如果有任何不清楚的地方,请发表评论。

【讨论】:

好的,谢谢,这很有帮助,而且工作正常。我可能会改变我索引文件的方式,这样我就可以让基于它的一切变得更有效率。但是,是的,非常感谢! @cwoebker - 没问题,很高兴它有帮助!祝你的问题好运! 感谢您的代码/操作方法@mac,它对我很有用,但我希望我的树在每个级别按字母顺序排序。我发现了这个:[链接]***.com/questions/21024969/…,但我没有让它与这棵树一起工作。谁能解释我如何正确使用“排序”功能或指向我一些关于此的“新手”课程。谢谢! 这是很棒的酱汁。但为什么它会取消排序我的排序输入? nm,我知道我可以简单地在 d.items 上添加一个排序操作【参考方案2】:

我并不完全清楚你拥有什么和你需要什么(提供一些你拥有的太慢的代码可能会有所帮助),但你可能应该将你的路径名分解为目录名和基本名,然后使用特制的类或至少是列表或字典的层次结构从中构建一棵树。然后各种遍历应该允许您以几乎任何您需要的方式进行序列化。

关于性能问题,您是否考虑过使用 Pypy、Cython 或 Shedskin?我有一个我一直在研究的重复数据删除备份系统,它可以在 Pypy 或 Cython 上运行相同的代码;在 Pypy 上运行它实际上优于 Cython 增强版本(在 32 位上运行很多,在 64 位上运行一点点)。我也很想比较 shedskin,但它显然无法跨越 shedskin/cpython 边界。

此外,当您遇到性能问题时,分析是必不可少的 - 至少,如果您已经选择了合适的算法。

【讨论】:

Cython 计划在以后使用。【参考方案3】:

首先,“非常高性能”“Python”不能很好地混合。如果您正在寻找将性能优化到极致,那么切换到 C 将为您带来远超您可能想到的任何智能代码优化的好处。

其次,很难相信“文件管理/分析工具包”中的瓶颈会是这个功能。磁盘上的 I/O 操作至少比内存中发生的任何事情慢几个数量级。分析您的代码是衡量这一点的唯一准确方法,但是……如果我错了,我准备付钱给你! ;)

我构建了一个愚蠢的测试功能只是为了进行一些初步测量:

from timeit import Timer as T

PLIST = [['dir', ['file', ['dir2', ['file2']], 'file3']], ['dir3', ['file4', 'file5', 'file6', 'file7']]]

def tree(plist, indent=0):
    level = []
    for el in plist:
        if isinstance(el, list):
            level.extend(tree(el, indent + 2))
        else:
            level.append(' ' * indent + el)
    return level

print T(lambda : tree(PLIST)).repeat(number=100000)

这个输出:

[1.0135619640350342, 1.0107290744781494, 1.0090651512145996]

由于测试路径列表是 10 个文件,并且迭代次数是 100000,这意味着在 1 秒内您可以处理大约 100 万个文件的树。现在...除非您在 Google 工作,否则这对我来说似乎是一个可以接受的结果。

相比之下,当我开始写这个答案时,我点击了主 80Gb HD 根目录上的“属性”选项[这应该给我上面的文件数量,使用 C 代码]。几分钟过去了,我大约有 50 GB,300000 个文件...

HTH! :)

【讨论】:

这确实很快,但与我的问题无关,我需要用正则表达式或其他东西分析我所有的路径,然后得到一个像你在输入中使用的树结构 @cwoebker - 你可能应该澄清你的问题,就像现在一样,不清楚你的输入和预期输出是什么。这也有助于了解您是否有权访问文件系统并可以从中读取文件名,或者您是否必须使用您希望举例说明的输入。 :) 我添加了示例输入...我确实可以访问文件系统。在项目中,我有一个 redis 实例中的文件索引,我从那里读取了路径,所以我不想再次访问这些文件 我认为在谈论 python 的高性能时提到切换到 c 是陈词滥调。每个人都知道这一点,但您并没有看到每个人都切换回 c。每种语言都有自己的目的,很明显 OP 意味着最快的算法,即在 Python 中实现的时间最短的算法。

以上是关于从列表 os 文件路径 (Python) 构造树 - 取决于性能的主要内容,如果未能解决你的问题,请参考以下文章

python小记操作文件

python:如何在(路径)列表上使用 os.path.isfile()? [复制]

python 中os.pardir啥意思

从 wpf 中的文件路径列表填充树视图

学习笔记——os模块常见列表

从路径列表中表示文件系统(文件/目录)的 Java 树