【问题标题】:Best cocoa data structure for list of files文件列表的最佳可可数据结构
【发布时间】:2009-11-16 09:06:12
【问题描述】:

我正在编写一个在运行时处理数百个文件的程序。现在每个文件和文件夹都存储在我创建的一个对象中(它包含文件路径、文件类型、文件大小、指向文件中偏移量的指针,以及是否是目录),这些对象被放置在 NSMutableArray 中。一个大问题是在处理所有文件结束时,我需要获取每个文件夹中所有文件的统计信息。我正在使用 2 个嵌套的 for 循环来执行此操作,性能很糟糕。

我的问题是:有没有更有效的方法来存储可可中的文件和文件夹列表(NSMutableArray、集合等除外),以便我可以快速访问这些文件夹中的所有文件夹和所有对象?是否有某种结构可以创建文件夹数组以及位于该父文件夹中的文件和文件夹数组?

【问题讨论】:

    标签: cocoa


    【解决方案1】:

    现在每个文件和文件夹都存储在我创建的一个对象中(它包含文件路径、文件类型、文件大小、指向文件中偏移量的指针,以及是否是目录),这些对象被放置在一个NSMutableArray.

    这是正确的解决方案。 C 数组比较棘手,因为您必须自己处理大小管理,而且您不会进行边界检查。

    这样做的一个大问题是在处理完所有文件时,我需要获取每个文件夹中所有文件的统计信息。我正在使用 2 个嵌套的 for 循环来执行此操作,性能很糟糕。

    您是否使用 Shark 和/或 Instruments 进行了分析?这是你应该检查的第一件事,如果你还没有。瓶颈可能不在您认为的位置。在您进行分析之前,请停止阅读此答案(以及任何其他答案)。


    如果您当前正在使用此任务阻塞主线程,请考虑改用 NSOperationQueue。对于顶层中的每个项目,如果是文件,则添加检查文件的操作,如果是目录,则添加将对目录内容执行相同迭代的操作。如果您需要 Snow Leopard,您会在这里找到方便的块,因为您不必明确告诉目录库存操作将检查文件操作添加到哪个队列。

    您可能应该限制队列一次运行的操作数量,以免最终运行太多。 Mike Ash has details(那篇文章是关于 GCD 的,但在 Snow Leopard 中,NSOperationQueue 是基于 GCD 的)。

    假设您在 UI 中显示运行总计,您可以使用主队列来保存(可能基于块)向总计添加新信息的操作。如果您支持 Leopard,您可以创建自己的“主”队列,但您必须自己让操作在主线程上运行。

    顺便说一下,如果您计算文件大小的总和,您应该考虑是否要在 inode 上进行唯一化。如果我将一个 200 MiB 的文件硬链接到其他三个地方,你会看到四个文件,但它们实际上都是同一个文件,所以它们只占用 200 MiB,而不是 800。

    【讨论】:

    • 带有线性搜索的循环循环,无论是在 C 数组上还是在多核的帮助下,仍然很糟糕。那是 O(n²) 算法。他需要为数组构建树或索引(哈希)。
    • 如果您在内部循环中为外部循环中的每个项目再次检查整个文件夹列表,则为 O(n²)。那不是他正在做的事情:对于他在外循环中遇到的每个文件夹,他检查内循环中该文件夹中的每个项目。据推测,他正在将它们添加到某种队列中以处理所有文件;我建议把它变成一个 NSOperationQueue。作为猜测,性能问题可能是从对象堆积中分页地狱,因此我的建议是(1)配置文件和(2)使用 NSOperationQueue(这意味着每个操作有一个自动释放池)。
    • 映射表将有助于 inode 唯一化,而树将防止在列表中同时包含文件夹及其祖先之一,但我看不出两者在一般情况下有何帮助离散目录树,没有硬链接。
    【解决方案2】:

    您可能还想考虑树状结构。您有一个对应于文件路径“/”的根节点。然后root有很多孩子,每个孩子都有“/System”、“/etc”、“/Library”、“/Users”等。

    当您将一个节点添加到此树中时,您可以让它向上渗透并将新节点的文件大小添加到父节点(以便树在根节点中始终具有正确的卷大小)。或者你可以让它根据你的需要计算大小(递归,最有可能)并返回它。

    至于首先检索路径,您可能已经找到NSFileManager。您还应该看看NSDirectoryEnumerator 和较低级别的FSGetCatalogInfoBulk

    【讨论】:

      【解决方案3】:

      您可以使用 C 数组而不是 Cocoa 集合。这可能会更快。
      一些性能比较链接:

      【讨论】:

      • 如果他有 O(n²) 算法,C 数组将无济于事。
      【解决方案4】:

      使用NSMutableDictionary 和文件目录作为键,NSMutableArray 文件作为对象。您将能够快速迭代目录。

      您还可以使用[NSString pathComponents] 拆分目录并使用字典字典来保存路径的每个部分(树)。您甚至可以在树中混合文件和字典,并使用[foo isKindOfClass:[NSDictionary class]] 将它们区分开来。

      这是我正在谈论的 JSON 版本(可以很好地转换为 Cocoa 类):

      /foo/bar/bazfile & /foo/quzfile =

      {"foo": {
         "bar": {
            "bazfile": fileinfo
         },
         "quzfile": fileinfo
      }
      

      【讨论】:

      • 阅读您的答案受到启发以解决另一个问题。欢呼
      猜你喜欢
      • 1970-01-01
      • 2017-09-26
      • 1970-01-01
      • 2013-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-08
      相关资源
      最近更新 更多