我想快速有效地列出单个目录中包含的大量文件(10,2万个左右)。 我已经阅读了很多帖子,特别是在这里解释了Java实现这一目标的短暂内容,主要是由于底层文件系统(可能Java 7有一些答案)。 这里的一些帖子提出了替代方案,如本机调用或管道等,我确实理解在正常情况下最好的选项是java调用 - String [] sList = file.list();这比file.listFiles()略胜一筹; 此外,还建议使用多线程(也是Executor服务)。
嗯,这里的问题是我对如何编写多线程方式的实用技巧很少。所以我的逻辑肯定是不正确的。不过,我试过这种方式:
像这样的东西,来电者班 -
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.来自apache commons的FileUtils.listFiles()
- 没有多大区别
2.本地电话即。 exec("cmd /c dir /B .\\Test")
- 这里执行速度很快,但是当我使用需要很长时间的while循环读取Stream时。
实际上我需要的是文件名,取决于单个目录中大约100k文件中的某个过滤器。所以我使用的是File.list(new FileNameFilter())
我相信FileNameFilter没有任何好处,因为它会首先尝试匹配所有文件,然后给出输出。
是的,我理解,我需要一种不同的方法来存储这些文件。我可以尝试的一个选项是将这些文件存储在多个目录中,我还没试过这个(我不知道这是否足够了) - 正如Boris之前的建议。
还有什么可以是更好的选择,对于具有文件名匹配的Unix ls的本机调用是否有效。我知道在Windows上它不起作用,我的意思是除非我们在同一目录中搜索
亲切的问候
答案 0 :(得分:6)
多线程对列出多个目录很有用。但是,您不能将单个调用拆分为单个目录,我怀疑如果操作系统以任何顺序返回文件,它会更快。
学习多线程的第一件事是,并非所有解决方案都只是通过使用多个线程来更快或更简单。
答案 1 :(得分:2)
这是一个完全不同的建议。你尝试过使用Apache Commons File util吗?
http://commons.apache.org/io/api-release/index.html查看方法FileUtils.listFiles()。
它将列出目录中的所有文件。也许它足够快并且足够优化以满足您的需求。也许你真的不需要重新发明轮子,解决方案已经在那里了?
答案 2 :(得分:0)
最终,我所做的是。
1.作为一个quickfix,为了解决这个问题,我使用本机调用将所有文件名写入临时文本文件,然后使用BufferedReader读取每一行。
2.编写实用程序以将非活动文件(大多数)存档到其他存档位置,从而减少活动目录中的总文件数。这样普通的list()调用返回得更快
3.作为一个长期的解决方案,我将修改所有这些文件的存储方式并创建一种目录层次结构,其中每个目录将保存相对较少的文件,因此list()可以非常快速地工作。
我想到了一件事情,我注意到测试时是这个列表(),当第一次运行需要很长时间但后续请求非常快。让我相信JVM无意中检索到堆上的列表。我尝试了一些事情,比如向dir添加文件或更改File变量名称,但响应仍然是即时的。所以我相信这个数组位于堆上直到gc'ed并且Java智能地响应相同的请求。 <*Am I right? or is that not how it behaves? some explanation pls.*>
因此,我想,如果我可以编写一个小程序来每天获取此列表并保留一个静态引用,那么这个数组将不会被gc'ed并且每个检索此列表的请求都会很快。 <*Again, some comments/suggestion appreciated.*>
有没有办法配置Tomcat,其中GC可能gc所有其他未引用的对象,但不适用于指定的那些?有人告诉我在Linux中这样的东西显然是针对操作系统级别实现的,我不知道它的真实与否。
答案 3 :(得分:0)
您使用的是哪个文件系统?每个文件系统对目录可以拥有的文件/文件夹数量(包括目录深度)有自己的限制。所以不确定如何创建,如果通过某个程序创建,你可以读回所有文件。
如上所述,FileNameFilter
是一个帖子文件名过滤器,因此我不确定它是否会有任何帮助(尽管您可能正在创建较小的文件列表列表)作为每个listFiles()
方法会得到完整的清单。
例如:
1)假设线程1正在捕获以“T * ”开头的文件名列表,listFiles()
调用将检索所有数千个文件名,然后根据FileNameFilter
条件进行过滤
2)如果捕获以“S *”开头的文件名列表,则线程2将重复从1开始的所有步骤。
因此,您多次读取目录列表会对Heap / JVM本机调用/文件系统等施加越来越多的负载。
如果可能,最好的建议是重新组织目录结构。