2010-12-10 113 views
1

我想快速高效地列出包含在单个目录中的大量文件(10,20,000左右)。 我已经阅读了不少帖子,特别是在这里解释了Java的短暂实现,主要由于底层文件系统(可能Java 7对此有一些答案)。 这里的一些帖子提出了诸如本地调用或管道等替代方案,并且我明白在正常情况下最好的选项是java调用 - String [] sList = file.list();这只比file.listFiles()稍微好点; 此外,还有一个使用多线程(也是Executor服务)的建议。Java:从单个目录中列出所有文件(10-20,000 +)

那么,这里的问题是我很少有如何编码多线程方式的实用知识。所以我的逻辑必然是错误的。不过,我想是这样的:

  1. 创建的对象
  2. 然此列表的环数线程的列表,称为。开始(),并立即。睡眠(500)
  3. 在线程类,过度骑着运行methos到包括.LIST()

这样的事情,主叫类 -

String[] strList = null; 
for (int i = 0; i < 5; i++){ 
    ThreadLister tL = new ThreadLister(fit); 
    threadList.add(tL); 
} 
for (int j = 0; j < threadList.size(); j++) { 
    thread = threadList.get(j); 
    thread.start(); 
    thread.sleep(500); 
} 
strList = thread.fileList; 

和Thread类作为 -

public String[] fileList; 
public ThreadLister(File f) { 
    this.f = f; 
} 
public void run() { 
    fileList = f.list(); 
} 

我可能会离开这里与多线程,我想这一点。 我非常感谢我的多线程要求的解决方案。额外的好处是我会学习更多关于实用多线程。

查询更新

那么,显然多线程是不是要帮我(以及我现在认识到它并不是一个真正的解决方案)。感谢您帮助我排除线程。
所以我试过了,
1. FileUtils.listFiles()来自apache commons--差别不大。
2.本地电话即, exec("cmd /c dir /B .\\Test") - 这里执行速度很快,但是当我使用需要时间的while循环读取Stream时。

实际上我需要的是文件名,取决于单个目录中大约100k个文件中的某个过滤器。所以我使用像File.list(new FileNameFilter())
我相信FileNameFilter没有任何好处,因为它会尝试首先匹配所有文件,然后发出输出。
是的,据我所知,我需要一种不同的方法来存储这些文件。我可以尝试的一个选择是将这些文件存储在多个目录中,但我还没有尝试过(我不知道这是否会有所帮助) - 正如鲍里斯之前提出的
还有什么可以是一个更好的选择,在Unix上的本地调用ls与文件名匹配有效地工作。我知道在Windows上它不工作,我的意思是,除非我们在同一个目录正在寻找

亲切的问候

+1

我也怀疑使用多线程将会有所帮助,因为没有办法告诉“list()”方法从哪里开始列出文件,所以你最终会重新创建列表多次。 – camickr 2010-12-10 16:25:53

+0

看来你必须退一步,重新思考将多个文件存储在一个目录中的实现。例如,看看苹果如何用他们的iPod解决了这个问题。有大约50个用于保存文件的文件夹。 – 2010-12-10 16:29:14

+0

@camickr - 是的,当我试图运行此程序时,它确实多次显示列表长度。 – 2010-12-10 16:46:29

回答

0

最终,我做了什么。
1.作为一个quickfix,为了解决这个问题,我使用本地调用将所有文件名写入临时文本文件,然后使用BufferedReader读取每一行。
2.编写一个实用程序将非活动文件(大部分)归档到其他归档位置,从而减少活动目录中的文件总数。所以正常的list()调用返回得更快。 3.但是,作为一个长期解决方案,我将修改所有这些文件的存储方式,并创建一种目录层次结构,其中每个目录将保留相对较少的文件,因此list()可以工作非常快。

有一件事出现在我的脑海里,当我第一次运行需要很长时间但后来的请求非常快时,我注意到当测试是这个列表()时。让我相信JVM不情愿地检索堆在一起的列表。我尝试了一些东西,例如将文件添加到目录或更改File变量名称,但仍然是即时响应。所以我相信这个数组会坐在堆上直到gc和Java智能地响应相同的请求。由于这个原因,我想,如果我可以编写一个小程序来每天获取一次这个列表并保留一个静态引用,那么这个数组将不会被gc化,并且每一个检索这个列表的请求都会很快。 <*Again, some comments/suggestion appreciated.*>
有没有办法配置Tomcat,其中GC可能gc所有其他未引用的对象,但不适用于某些指定的对象?有人在Linux中告诉我这样的事情显然是在OS级别实现的,但我不知道它是否正确。

5

多线程是列出多个目录非常有用。然而,你不能将一个单独的调用分割到一个单独的目录中,并且如果你可以按照任意顺序返回文件,我怀疑它会更快。

学习多线程的第一件事就是,并不是所有的解决方案都会使用多线程更快或更简单。

2

上午作为一个完全不同的建议。你有没有尝试使用Apache Commons File util?

http://commons.apache.org/io/api-release/index.html检出FileUtils.listFiles()方法。

它会列出目录中的所有文件。也许它足够快并且足够满足您的需求。也许你真的不需要重新发明轮子,解决方案已经在那里了?

+0

@ Apache - 感谢这个建议,我也会试着实现这个。 – 2010-12-10 16:50:48

0

您正在使用哪种文件系统?每个文件系统对于目录可以具有的文件/文件夹的数量(包括目录深度)有其自身的限制。所以不知道你如何创建,如果通过某些程序创建,你可以读取所有文件。

如上面建议的FileNameFilter是一个过帐文件名过滤器,所以我不确定它是否会有帮助(尽管您可能会创建较小的文件列表),因为每个listFiles()方法都会得到完整列表。

例如: 1)假设线程1捕获开始以“T * ”文件名列表,listFiles()调用会检索所有数以千计的文件名,然后过滤按FileNameFilter标准 2)螺纹2,如果捕获以“S *”开头的文件名列表将重复从1开始的所有步骤。

因此,您多次阅读目录列表,将越来越多地加载到Heap/JVM本地调用/文件系统上。

如果可能,最好的建议是重新组织目录结构。

+0

你从第二个电话看到更好的回应的原因可能是由于多种原因: 1)操作系统可能本机缓存目录结果(将其带到内存)并保留一段时间 - 一个好的测试将是在第一次运行一小时左右后再次列出文件。 2)JVM是缓存的,因为所有的修改都是通过你的java程序执行的,它正在修改缓存中的文件列表(我严重怀疑这种方法,因为JVM不能够读取外部修改 - 陈旧列表) – Rajendra 2011-03-10 15:35:09

+0

仍然不明白你为什么写了一个本地调用来将目录列表写入文件。您可以使用Runtime.exec命令来处理文件并将其写入列表。 list()/ listFiles()命令本身使用本地调用来检索文件系统。如果列表太大,您可能会遇到内存问题。 – Rajendra 2011-03-10 15:36:12