以Java递归计算目录大小但不包括重复项

时间:2012-11-06 19:51:30

标签: java

我写了一个小函数来计算目录中所有文件的大小。实际的功能做得更多,但这个例子用于简洁。

这是可行的,并且递归地遍历目录很容易,但我想排除已经处理过的所有文件名。我想跟踪List中的所有文件名,以便在获取文件大小之前,检查它是否存在于List中,如果存在,则应将其排除。我不想要任何MD5校验和或任何东西。文件名对我的情况来说已经足够了。

由于我只能从函数返回一个值而Java不允许传递引用,所以我很遗憾实现它的最佳方法是什么。这是我的代码:

public static Long getFileSize(File dirDirectory) {
    Long lngSize = new Long(0);

    for (File filItem : dirDirectory.listFiles()) {
        if (filItem.isDirectory()) {
            lngSize += getFileSize(filItem);
        }
        else {
            //Is a file with the same filename alrwady been calculated
            //then exclude it
            //else
            //include it.
            lngSize += filItem.length();
        }
    }

    return lngSize;
}

6 个答案:

答案 0 :(得分:3)

请勿使用List,请使用HashSet。列表将使用O(n)查找来查看文件是否存在,而HashSet将使用O(1)

通过将方法设为public并将辅助函数设为私有,您不会将HashSet实现暴露给程序的其余部分(它不会也不应该关心它)。

public static Long getFileSize(File dirDirectory) {
    return getFileSize(File dirDirectory, new HashSet<File>());
}

private static Long getFileSize(File dirDirectory, HashSet<File> prevProcess) {
    Long lngSize = new Long(0);

    for (File filItem : dirDirectory.listFiles()) {
        if (prevProcess.contains(filItem) continue;
        if (filItem.isDirectory()) {
            lngSize += getFileSize(filItem);
        }
        else {
            lngSize += filItem.length();
        }
        prevProcess.add(filItem);
    }

    return lngSize;
}

答案 1 :(得分:1)

你可以这样做:

public static Long getFileSize(File dirDirectory) {
    return getFileSize(dirDirectory, new HashSet<String>());
}

public static Long getFileSize(File dirDirectory, Set<String> previouslyProcessedFiles) {
    //DO IT HERE AS YOU WISH
}

答案 2 :(得分:0)

传递一个Set:

public static Long getFileSize(Set<File> alreadySeen, File dirDirectory) {
    long lngSize = 0;

    for (File filItem : dirDirectory.listFiles()) {
        if (filItem.isDirectory()) {
            lngSize += getFileSize(filItem);
        }
        else {
            //Is a file with the same filename alrwady been calculated
            //then exclude it
            //else
            //include it.
            if (! alreadySeen.contains(filItem.getName())) {
                alreadySeen.add(filItem.getName());
                lngSize += filItem.length();
            }
        }
    }
    return lngSize;
}

致电:

Long size = getFileSize(new HashSet<File>(), myDirectory)

此外,您最好使用long计数器而非Long,以避免Java需要不断取消装箱/重新装箱。

顺便说一句,在没有递归的情况下遍历目录树很简单,只需将您遇到的目录添加到稍后要处理的列表中:

public static Long getFileSize(File dirDirectory) {
    long lngSize = 0;
    Deque<File> unprocessedDirs = new ArrayDeque<File>();
    unprocessedDirs.add(dirDirectory);
    Set<File> alreadySeen = new HashSet<File>();
    while (!unprocessedDirs.isEmpty()) {
        File dir = unprocessedDirs.removeFirst();

        for (File filItem : dir.listFiles()) {
            if (filItem.isDirectory()) {
                unprocessedDirs.addFirst(filItem); 
            }
            else {
                //Is a file with the same filename alrwady been calculated
                //then exclude it
                //else
                //include it.
                if (! alreadySeen.contains(filItem.getName())) {
                    alreadySeen.add(filItem.getName());
                    lngSize += filItem.length();
                }
            }
        }
    }
    return lngSize;
}

答案 3 :(得分:0)

这个怎么样:

public static Long getFileSize(File dirDirectory, List<String> processed) {
    Long lngSize = new Long(0);

    for (File filItem : dirDirectory.listFiles()) {
        if (filItem.isDirectory()) {
            lngSize += getFileSize(filItem, processed);

        } else {
            String filName = filItem.getName();
            if (processed.contains(filName)) {
                continue;
            }
            lngSize += filItem.length();
            processed.add(filName);
        }
    }

    return lngSize;
}

答案 4 :(得分:0)

您可以使用全局变量或将列表作为参数传递给函数。 但我的建议不是使用List,而是使用Set,特别是TreeSet或HashSet。

您不需要存储重复项,并且您必须在完整列表中搜索文件名 - 在列表O(n)中非常昂贵的操作。一个集合将防止重复,但特别是HashSet是O(n)而TreeSet是O(ln n) - 使搜索更快

请参阅:Hashset vs Treeset

答案 5 :(得分:0)

我建议您使用内置过滤器FileFilterFilenameFilterFile.listFiles()方法。这样它更优雅,更直观。

public class FileSizeCalculator {

    public static void main(String[] args) {
        System.out.println(getFileSize(new File(".")));
    }

    public static Long getFileSize(File directory) {

        FileFilter uniqueFilter = new FileFilter() {
            Set<File> uniqueFiles = new HashSet<File>();
            @Override
            public boolean accept(File file) {
                /**
                 * This will return true only if this set 
                 * did not already contain the specified element
                 */
                return uniqueFiles.add(file);
            }
        };

        long size = 0L;
        for (File file : directory.listFiles(uniqueFilter)) {
            size += file.isDirectory() ? getFileSize(file) : file.length();
        }
        return size;
    }
}