问题 当列表文件在目录中时OutOfMemory


当我列出包含300,000个带Java文件的目录的文件时,会发生内存不足。

String[] fileNames = file.list();

我想要的是一种方法,可以逐步列出目录的所有文件,无论该特定目录中有多少文件,并且没有默认64M堆限制的“内存不足”问题。

我有谷歌一段时间,并没有在纯Java中找到这样的方式。
请帮帮我!!

注意,JNI是一种可能的解决方案,但我讨厌JNI。


3058
2018-01-13 04:08


起源

64MB堆限制要求是难的吗?您是否还有代码的其他部分分配了大量对象? - notnoop
64MB不是硬限制。但是,我们希望使用java来监视客户上传大量文件的文件夹。我们不知道有多少内存就足够了。 - James
一旦列出了所有内容,您将如何处理结果? - OscarRyz
如同 stackoverflow.com/questions/3139073/... - Renaud


答案:


我知道你说“使用默认的64M堆限制”,但让我们看一下事实 - 你希望使用Java提供的机制在内存中保存(可能)大量项目。所以,除非有一些可怕的原因你不能,我会说增加堆是要走的路。

以下是JavaRanch中相同讨论的链接: http://www.coderanch.com/t/381939/Java-General/java/iterate-over-files-directory

编辑,回应评论:我说他想在内存中保存大量项目的原因是因为这是Java为列出目录而不使用本机接口或特定于平台的机制提供的唯一机制(并且OP说他想要“纯Java”)。


5
2018-01-13 04:14



詹姆斯正在进行的调用返回一个数组。问题可以归结为是否可以以某种方式获得目录中名称的等效迭代器,而无需立即分配完整数组。这是一个合理的问题;我不知道我的答案。 - Dan Breslau
你不能使用核心Java API。 - danben
是的,我想要的只是一个FileIterator - James


唯一可行的解​​决方案是Java7,然后你可以使用迭代器。

final Path p = FileSystems.getDefault().getPath("Yourpath");
Files.walk(p).forEach(filePath -> {
        if (Files.isRegularFile(filePath)) {
            //Do something with filePath
        }
});

4
2017-07-23 07:00



在 stackoverflow.com/questions/3139073/... 我已经发布了一个如何使用Java 7完成此操作的简单示例 - Jaime Hablutzel
Path.iterator() 迭代路径的名称元素,而不是目录中的文件。 - predi


你在这里有点不走运。至少需要创建300k字符串。平均长度为8-10个字符,每个字符2个字节,最小为6Mb。每个字符串添加对象指针开销(8个字节),然后进入内存限制。

如果你必须在一个目录中拥有那么多文件,我不建议你因为你的文件系统会有问题,你最好的办法是通过Runtime.exec运行一个本机进程(而不是JNI)。请记住,您将自己绑定到操作系统(ls vs dir)。您将能够将文件列表作为一个大字符串获取,并负责将其后处理为您想要的内容。

希望这可以帮助。


2
2018-01-13 04:19





在目录中有30万个文件并不是一个好主意 - AFAIK文件系统不擅长在单个节点中拥有那么多子节点。但有趣的问题。

编辑:以下没有帮助,看到评论。

我认为你可以使用FileFilter,拒绝所有文件,并在过滤器中处理它们。

        new File("c:/").listFiles( new FileFilter() {
            @Override   public boolean accept(File pathname) {
                processFile();
                return false;
            }
        });

1
2018-01-13 04:16



XFS在单个目录中支持大量文件。此外,这个答案离主题很远。 - danben
刚刚检查了java.io.File的源代码。它会在过滤之前调用列表,因此原始问题仍然存在。 - Gennadiy
是的,我希望人们在修改之前至少验证“看起来正确”的答案。海报没有违法行为。 - danben
好吧,谁能知道JDK程序员那么傻呢?离开这里,以警告其他人。 - Ondra Žižka
我一直忘记JDKs FileSystem抽象。返回String文件名数组的实际list方法是本机的,因此几乎没有希望能够检索dir中的部分文件列表。 - Gennadiy


如果您可以使用Java 7或更高版本编写代码,那么以下是一个不错的选择。

Files.newDirectoryStream(Path dir)

这里 是API的java文档。

希望这可以帮助。


0
2017-07-01 08:37