如何在java中列出200万个文件目录而不会出现“内存不足”异常
2022-09-02 00:54:27
我必须处理一个大约200万个要处理的xml的目录。
我已经解决了使用队列在机器和线程之间分配工作的处理,一切都很顺利。
但现在最大的问题是读取包含200万个文件的目录的瓶颈,以便增量填充队列。
我尝试过使用这种方法,但它给了我一个java异常。有什么想法吗?File.listFiles()
out of memory: heap space
我必须处理一个大约200万个要处理的xml的目录。
我已经解决了使用队列在机器和线程之间分配工作的处理,一切都很顺利。
但现在最大的问题是读取包含200万个文件的目录的瓶颈,以便增量填充队列。
我尝试过使用这种方法,但它给了我一个java异常。有什么想法吗?File.listFiles()
out of memory: heap space
首先,你有没有可能使用Java 7?在那里,您有 一个 和 ,它们可能应该在您的内存约束内工作。FileVisitor
Files.walkFileTree
否则,我能想到的唯一方法是将File.listFiles(FileFilter过滤器)
与始终返回false
(确保整个文件数组永远不会保存在内存中)的过滤器一起使用,但该过滤器捕获要在此过程中处理的文件,并可能将它们放在生产者/消费者队列中或将文件名写入磁盘以供以后遍历。
或者,如果您控制文件的名称,或者如果它们以某种很好的方式命名,则可以使用接受表单上的文件名的过滤器(然后-等)按块处理文件。file0000000
filefile0001000
file0001000
filefile0002000
如果名称不是以这样好的方式命名的,您可以尝试根据文件名的哈希代码过滤它们,这应该在整数集上相当均匀地分布。
更新:叹息。可能不起作用。刚刚看了一下 listFiles 的实现:
public File[] listFiles(FilenameFilter filter) {
String ss[] = list();
if (ss == null) return null;
ArrayList v = new ArrayList();
for (int i = 0 ; i < ss.length ; i++) {
if ((filter == null) || filter.accept(this, ss[i])) {
v.add(new File(ss[i], this));
}
}
return (File[])(v.toArray(new File[v.size()]));
}
所以无论如何,它可能会在第一行失败...有点令人失望。我相信你最好的选择是把文件放在不同的目录中。
顺便说一句,你能举一个文件名的例子吗?它们是“可猜测的”吗?喜欢
for (int i = 0; i < 100000; i++)
tryToOpen(String.format("file%05d", i))
如果Java 7不是一个选项,这个黑客将起作用(对于UNIX):
Process process = Runtime.getRuntime().exec(new String[]{"ls", "-f", "/path"});
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while (null != (line = reader.readLine())) {
if (line.startsWith("."))
continue;
System.out.println(line);
}
-f 参数将加快速度(从):man ls
-f do not sort, enable -aU, disable -lst