2012-11-14 42 views
1

使用Python从目录获取单个文件的最有效和最快速的方法是什么?从目录中获取单个文件的最有效/最快的方法

关于我的具体问题的更多细节:
我有一个包含大量预生成文件的目录,我只想随机选择一个目录。因为我知道从一个目录中选取一个随机文件没有真正有效的方法,除了首先列出所有文件之外,我的文件是以一个已经随机的名字生成的,因此它们已经被随机排序了,我只需要选择第一个文件夹中的文件。

所以我的问题是:如何从我的文件夹中选择第一个文件,而无需从目录加载整个文件列表(也没有操作系统这样做,我的最佳目标是强制操作系统只是给我一个单一的文件,然后停止!)。

注意:我的目录中有很多文件,因此为什么我想避免列出所有文件以选择一个文件。注意2:每个文件只选择一次,然后删除,以确保下次只有新文件被选中(从而确保某种随机性)。

SOLUTION

我最终选择使用将存储的索引文件:

  • 要被拾取的当前文件的索引(例如:1 file1.ext,2 file2的.EXT,等..)
  • 产生的最后一个文件的索引(如:1999年file1999.ext)

当然,这意味着我的文件s的不是一个随机名称生成了,但是使用确定性递增的模式(例如:“文件%s.ext”%ID)

因此,我有我的两个主要业务接近恒定的时间:

  • 访问文件夹中的下一个文件
  • 计算剩余的文件数(以便我可以在需要时在后台线程中生成新文件)。

这是我的问题的具体解决方案,对于更通用的解决方案,请阅读接受的答案。

而且你可能有兴趣进入这两个其他的解决方案,我发现用Python优化的文件和目录行走的访问:只需使用random.choice()

+0

想一想,然后建立你自己的数据库,使其更快? – PearsonArtPhoto

+0

目录*不*排序。相反,他们列出当前目录结构顺序(磁盘结构)中的项目,这可能是创建顺序。 –

+0

我避免使用DBMS的原因,因为我不需要任何排序的任何索引。我不想选择特定的文件,只是任何文件,只有一个文件。 @Martijn:我说的是一个简化,以更好地传达我的想法。文件按inode排序,但这不是重点:我只想得到第一个文件,因为我的文件已经是随机的了,所以我不必在意随机选择一个文件:只选择此目录中的任何文件给我一个随机的结果。 – gaborous

回答

1

创建文件时,将最新文件的名称添加到存储在文本文件中的列表中。当你想读/工艺/删除文件:

  1. 打开文本文件
  2. 设置文件名,在列表顶部的名称。
  3. 从列表
  4. 关闭文本文件
  5. 进程文件名的顶端删除名称。
+0

很好的解决方案。事实上,鉴于我给出的问题描述,这是最好的。我们还可以对其进行增强:在文件生成时,在文件末尾添加新名称而不是顶部(避免打开并读取整个文件),在文件访问时只需读取第一行并将其从文本文件中删除(I确定有办法做到这一点,而不必阅读整个文件)。我将这个解决方案标记为公认的答案,虽然[Lucasmus给出的解决方案也非常聪明](http://stackoverflow.com/a/13378514/1121352)。 – gaborous

+1

在我的最终解决方案中,我将实现索引概念的另一种变体:我不会随机生成名称,而是使用具有增加编号的确定性模式(例如:file1.ext,file2.ext,file3.ext等。 )。然后,我将保留一个索引文件,该文件将存储2个字段:当前ID(例如:file1.ext为1)以及最近生成的文件的最后一个ID(例如:1999 for file1999.ext)。这有几个好处:索引文件总是很短;我总是可以直接访问一个新文件;最后,我还可以通过计算latestID - currentID来计算剩余的文件数量,而不用列出文件 – gaborous

+0

,这允许我运行后台线程,以便在指定阈值下运行时生成新文件。最后,我们对这两个操作获得几乎不变的访问时间:访问文件并计算剩余文件的数量。 Con是我必须小心对索引文件和生成的文件进行并发访问,以避免不同步(作为一种失败防护,当遇到try:exception之外的异常时,我可以重新生成它)。 – gaborous

1

os.listdir()结果:

import random 
import os 

randomfilename = random.choice(os.listdir(path_to_directory)) 

os.listdir()返回由OS给出的顺序的结果。使用随机文件名不会改变该顺序,只有将项目添加到目录或从目录中删除项目才能影响该顺序。

如果您担心文件太多,请勿使用单个目录。相反,建立一个预先生成名称的目录树,随机挑选其中一个,然后从那里选择一个文件。

+0

正如我所说,我的文件已经随机生成,所以没有必要使用random.choice()。 此外,您的解决方案仍然列出目录中的所有文件,如果我有大量文件(这是我的情况),这将非常慢。 – gaborous

+1

@ user1121352:使用随机文件名*不会创建随机顺序*。 –

+0

我知道,但随机文件名+第一次访问后删除文件会生成随机顺序。这是一种扭曲[无需更换抽样](http://www.ma.utexas.edu/users/parker/sampling/repl.htm) – gaborous

2

在1个目录中没有大量预生成文件。如果目录中的'n'个文件超过子目录,则将它们分割。

+1

这不是一个解决方案:我仍然必须列出所有文件夹,然后列出我将访问的子目录中的所有文件,以知道还剩下多少预生成文件来选择是否删除该文件夹。如果我不这样做,从长远来看,我会得到很多空文件夹,我仍然会走路并浪费CPU周期。 – gaborous

+0

不正确。列出文件夹不需要太多时间,因为只有n个文件夹才能列出。然后,您从文件夹下降到文件夹,直到找到文件。使用后,您删除该文件并检查文件夹是否为空。如果这样删除该文件夹。以递归方式进行此操作,您将显着减少列出的文件数量。(我的意思是你递归地在文件夹上划分文件,所以文件夹也可以包含子文件夹。)如果我是正确的,这将把你从O(N)列出的文件减少到O(n-root(N)) 。 –

+0

好的我明白你的意思了。事实上,如果我们把想法扩展到最大限度,这是一种递归算法,但是对于文件放置而不是数据处理:为了最大限度地发挥其潜力,我们可以将每个文件放在它自己的文件夹中(因此每个文件夹一个文件!)每2个文件夹递归放置在一个文件夹内。这样,我们将创建一个log2(N)个杠杆(根为N/2 ** log2(N))的树。复杂性会像O(n * log2(N))一样,但我们必须使用主定理来获得更精确的结果。 (在下一个评论中继续) – gaborous

相关问题