0

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

这很有效,递归地遍历目录很容易,但我想排除所有已经处理过的文件名。我想跟踪 a 中的所有文件名,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;
}
4

6 回答 6

3

Don't use a List, use a HashSet. A list will use O(n) lookups to see if the file is there, whereas a HashSet will use O(1).

By making the method public and the helper function private, you don't expose the HashSet implementation to the rest of your program (which doesn't and shouldn't care about it).

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;
}
于 2012-11-06T20:00:26.003 回答
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
}
于 2012-11-06T19:56:57.970 回答
0

传递一组:

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;
}
于 2012-11-06T20:01:14.820 回答
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;
}
于 2012-11-06T20:01:56.733 回答
0

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

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

请参阅:哈希集与树集

于 2012-11-06T20:02:42.660 回答
0

我建议您使用内置过滤器或FileFilter方法。这种方式更加优雅和直观。FilenameFilterFile.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;
    }
}
于 2012-11-06T20:31:18.763 回答