Java数据结构文件StackOverflowError

时间:2013-10-25 17:58:12

标签: java linux java-io stack-overflow

我的程序将计算机上的所有文件路径(OS Ubuntu)收集到一个 Map Map 中的键是文件大小,值是文件的规范路径列表,大小等于key。

Map<Long, ArrayList<String>> map = new HashMap<>(100000);

计算机上的文件总数为: 281091

收集文件的方法,它是递归的。

private void scanner(String path) throws Exception {

        File[] dirs = new File(path).listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {

                if (file.isFile() && file.canRead()) {

                    long size = file.length();

                    String canonPath = file.getCanonicalPath();

                    if (map.containsKey(size))
                        map.get(size).add(canonPath);

                    else map.put(size, new ArrayList<>(Arrays.asList(canonPath)));

                    return false;
                }
                return file.isDirectory() && file.canRead();
            }
        });

        for (File dir : dirs) {
            scanner(dir.getCanonicalPath());
        }
    }

当我开始从根文件夹开始扫描时,“/”有异常:

Exception in thread "main" java.lang.StackOverflowError
    at java.io.UnixFileSystem.canonicalize0(Native Method)
    at java.io.UnixFileSystem.canonicalize(UnixFileSystem.java:172)
    at java.io.File.getCanonicalPath(File.java:589)
    at taskB.FileScanner.setCanonPath(FileScanner.java:49)
    at taskB.FileScanner.access$000(FileScanner.java:12)
    at taskB.FileScanner$1.accept(FileScanner.java:93)
    at java.io.File.listFiles(File.java:1217)
    at taskB.FileScanner.scanner(FileScanner.java:85)
    at taskB.FileScanner.scanner(FileScanner.java:109)
    at taskB.FileScanner.scanner(FileScanner.java:109)
    ...

但是对于测试我填写目录“〜/ Documents”超过 400 〜千个文件并开始从中扫描。一切正常。

为什么当程序从根目录“/”开始时,我的异常少了30万个文件?我应该怎么做才能防止这种情况发生?

3 个答案:

答案 0 :(得分:1)

StackOverflow意味着您调用了如此多的嵌套函数,使得程序在内存空间中用尽函数调用信息(从调用返回后保留)。在你的情况下,我怀疑这是由于解析“。” (当前目录)和“..”(父目录)条目在目录列表中返回时,因此您可以多次递归到同一目录。

答案 1 :(得分:1)

最可能的解释是,在文件系统中的某处创建一个符号链接,创建一个循环(无限循环)。例如,以下是一个循环

  /home/userid/test/data -> /home/userid

扫描文件时,您需要忽略指向目录的符号链接。

答案 2 :(得分:1)

@Jim Garrison是对的,这是由于符号链接。解决他们发现here的问题。

我使用isSymbolicLink(Path)方法。

return file.isDirectory() && file.canRead() && !Files.isSymbolicLink(file.toPath());