【问题标题】:Selecting a file randomly from a file system从文件系统中随机选择一个文件
【发布时间】:2011-09-02 05:47:52
【问题描述】:

这个问题与Simulating file system access 有关。

我需要随机选择文件和目录作为重命名、写入、读取等文件操作的参数。我打算做的是列出所有文件和目录及其路径并从中随机选择列表。但是,随着在实际文件系统中创建和删除文件和目录,列表也必须更新。我发现以这种方式维护和更新列表效率低下,而且它还必须是原子的,以便以后的操作不会访问被先前操作删除的文件。

您能否建议一种不同的方式来选择文件..也许可以直接从文件系统中进行...但是我们如何知道文件的路径。

谢谢

我在这里Randomly selecting a file from a tree of directories in a completely fair manner 发现了一些有趣的东西,特别是在 Michael J. Barber 的回答,但由于我对 python 的无知,无法完全理解它

【问题讨论】:

  • 我的回答几乎描述了他的临时解决方案。随机化最大深度应该会有所帮助。我认为这个问题的最大区别在于它涉及文件系统的子树。我不想为了确保每个文件都有平等的机会被选中而不断地从根目录走动。
  • 该操作不必是“原子的”——在(从缓存列表中)选择一个文件后,可以测试它是否存在。另一部分(不使用各种通知系统)可能会变得相当昂贵。
  • @pst...啊哈,没想到像测试存在这样简单的事情。谢谢。没有明白你的意思,“另一位(不使用各种通知系统)可能会变得相当昂贵”
  • @Juggler 读取文件系统上的每个文件 ;-)
  • @pst 我已经说过了,你怎么会得到支持? :)

标签: c linux filesystems


【解决方案1】:

当文件系统就在那儿时,您不想尝试维护文件列表。您应该可以直接从 C 中执行此操作。从根目录步行,从中选择一个随机文件。您可以选择一个随机的最大深度,如果您在此之前或之前点击常规文件,请使用它。如果它是一个目录,重复到最大深度。如果是特殊文件,可以重新开始。

这应该很快。该操作不必是原子的。如果您想要执行操作时文件不存在,请重试。不应该太复杂。您可以在找到目标文件时构建路径。这将比直接使用 fs 更简单(我假设您的意思是低得多的级别)并且应该易于实现。

【讨论】:

  • 我认为分布会因结构而异。
  • @keith.layne 怎么会是随机的?我的意思是当我从根目录走时,我总是会沿着相同的路径沿着相同的子树走,因此从某些子树中选择文件的概率会更高。事实上,有些文件可能永远不会被选中。我可能不明白你的做法。
  • 如果从根中随机选择,为什么总是走同一条路?当然,随机通常在计算机上不是随机的。随机意味着每个文件都有完全相同的机会被选中。我是说这个目标太昂贵了。如果您正在模拟文件访问,那么您只需要足够随机即可满足您的模拟要求。
  • @pst 你是绝对正确的......你也许可以修改我的算法以具有随机目标深度而不是最大深度。这可能会有所帮助。如果你不走整棵树,这个问题是一个合理的上限。
  • 这不是完全随机的:如果/包含两个目录,/foo/bar,分别包含一个文件和一百万个文件,那么/foo/alone的概率将远大于/bar/oneGrainOfSandOnTheBeach。 +1 直接使用文件系统。
【解决方案2】:

这是我提出的解决方案。它不是最快的,但应该很快(在准备之后),只使用适度的内存,并且“分布得相当好”。当然,这是 100% 未经测试且有些复杂(与维护 RB-tree 或类似的东西一样复杂,无论如何)——我不得不使用 C ;-)

  1. 对于目标域中的每个目录,使用文件系统的深度优先遍历构建目录树,并记录“之前”文件计数(迄今为止在树中找到的文件)和“之后”文件计数(“之前”计数加上目录中的文件数)。它不应该存储文件本身。 Fast way to find the number of files 给出了一些示例 C 代码。它仍然需要迭代目录内容,但不需要存储文件本身。

  2. 计算树中文件的总数。 (这实际上应该只是树中最后一个节点的“之后”计数。)

  3. 在 [0, max files) 范围内选择一个随机数。

  4. 导航到树中的节点,使得“之前”文件计数

  5. 在与所选节点关联的目录中选择一个随机文件 -- 确保再次计算该目录并将其用作选择中的 [0, limit] (在流失的情况下使用后备-the-end 由于并发问题)。如果文件数量发生变化,请确保使用此类信息更新树。如果目录已被删除等,还要更新/修复树。(这里的额外完整计数不应该像听起来那么糟糕,因为readdir(平均而言)必须已经通过 1/2 的条目导航目录。但是,应该探索重新计数的好处(如果有的话)。)

  6. 根据需要重复步骤 2-5。

定期重建整个树(步骤 #1)以解决文件系统更改。删除/添加文件会慢慢地扭曲随机性——步骤 #5 可以帮助在某些情况下更新树。重建频率应通过实验确定。也可以通过每次通过重建父/祖父节点或 [随机] 子节点等来减少错误引入。使用修改后的时间作为检测更改的快速方法也可能值得研究。

编码愉快。

【讨论】:

  • 在我非常小的 linux 虚拟机安装中,fsck 告诉我/dev/sdb1: 340669/8536064 files。我不记得哪个数字很重要,但我敢打赌它是第二个。多长时间做一个DFS?如果不在整个 FS 上,为什么要模拟 FS 访问?我是不是误会了,它只是一个子树?我只是想以极小的时间和空间要求进行体面的分发。
  • @keith.layne 整个树结构(对于任何需要的根,据我所知,它可能只需要在 /opt 上,这与使用它作为根没有什么不同,而不是 / , 只是一棵树的开始 ;-) 被读取——但只保留结构本身和文件计数。它只需要标准的 POSIX API,因此与原始文件系统或特定 [内核级] 功能的更“动手”方法相比,它可能相对较慢。至于“多长时间”,这取决于环境因素(该步骤不便宜 - 更改后的措辞),这就是为什么摊销修正可能是有益的。
  • @keith.layne 值得一提的是,WinDirStat 花了 30 秒时间扫描 SSD 上 Windows 7 中 38k 目录中的 197k 文件。
  • @pst 是的,我试图让 OP 澄清一下。我正在跟踪 POSIX fs 调用(毕竟他将其标记为linux),正如我所提到的,我也不会弄乱原始文件系统。需要明确的是,我同意你的算法比我的算法要好得多如果随机性是最重要的因素如果 DFS 不需要很长时间来准备让你睡着了等待它。不相信摊销(如您所说,收益取决于许多环境因素)折扣足以使其实用......如果@Juggler 给我们一个粗略的文件数,它会有所帮助。
  • @pst 这真是太棒了......很好奇它如何处理旋转磁盘上的 10x 文件......你有机会提供吗?负载在 1.0 左右?
【解决方案3】:

您应该知道每个目录中有多少文件,以便选择您应该遍历的目录。避免遍历符号链接和计算符号链接中的文件。

您可以使用与 pst 描述的类似的解决方案。

例如,您有 3 个目录,每个目录有 20,40 和 1000 个文件。 你总计 [20,60,1060] 并选择随机数 0-1060。如果此数字大于或等于 60,则转到第三个文件夹。

一旦到达没有文件夹的文件夹,您就会停止遍历。

要通过此路径查找随机文件,您可以使用与以前相同的技巧。

这样你会选择任何概率相等的文件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-15
    • 1970-01-01
    • 1970-01-01
    • 2014-07-29
    • 2021-08-03
    • 1970-01-01
    • 2012-03-03
    相关资源
    最近更新 更多