1. 概述
在本教程中,我们将学习如何使用 Java 来获取文件夹的大小。内容涵盖从 Java 6、Java 7 到 Java 8 的实现方式,同时也包括使用 Guava 和 Apache Commons IO 的方法。
最后,我们还会展示如何将目录大小转换为人类可读的格式(如 KB、MB 等)。
2. 使用 Java 原生方式
我们先从一个基础的递归方法开始,通过累加目录中所有文件的大小来计算整个目录的大小:
private long getFolderSize(File folder) {
long length = 0;
File[] files = folder.listFiles();
int count = files.length;
for (int i = 0; i < count; i++) {
if (files[i].isFile()) {
length += files[i].length();
}
else {
length += getFolderSize(files[i]);
}
}
return length;
}
可以这样测试 getFolderSize()
方法:
@Test
public void whenGetFolderSizeRecursive_thenCorrect() {
long expectedSize = 12607;
File folder = new File("src/test/resources");
long size = getFolderSize(folder);
assertEquals(expectedSize, size);
}
⚠️ 注意:listFiles()
方法用于列出目录中的所有内容。
3. 使用 Java 7 NIO.2
在 Java 7 中,我们可以使用 Files.walkFileTree()
方法遍历文件树,从而更优雅地处理目录大小的计算:
@Test
public void whenGetFolderSizeUsingJava7_thenCorrect() throws IOException {
long expectedSize = 12607;
AtomicLong size = new AtomicLong(0);
Path folder = Paths.get("src/test/resources");
Files.walkFileTree(folder, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
size.addAndGet(attrs.size());
return FileVisitResult.CONTINUE;
}
});
assertEquals(expectedSize, size.longValue());
}
✅ 这里我们使用了文件树遍历 + 访问者模式,代码结构清晰,易于扩展。
4. 使用 Java 8 Stream API
Java 8 引入了 Stream API,可以用更函数式的方式实现目录大小计算:
@Test
public void whenGetFolderSizeUsingJava8_thenCorrect() throws IOException {
long expectedSize = 12607;
Path folder = Paths.get("src/test/resources");
long size = Files.walk(folder)
.filter(p -> p.toFile().isFile())
.mapToLong(p -> p.toFile().length())
.sum();
assertEquals(expectedSize, size);
}
✅ 使用 Files.walk()
遍历路径,结合 filter
和 mapToLong
,最后通过 sum()
得到总大小,代码简洁高效。
5. 使用 Apache Commons IO
如果你的项目中已经引入了 Apache Commons IO,那么获取目录大小就非常简单了:
@Test
public void whenGetFolderSizeUsingApacheCommonsIO_thenCorrect() {
long expectedSize = 12607;
File folder = new File("src/test/resources");
long size = FileUtils.sizeOfDirectory(folder);
assertEquals(expectedSize, size);
}
⚠️ 注意:这个方法内部其实也是用 Java 6 的递归实现的。
此外,还有 FileUtils.sizeOfDirectoryAsBigInteger()
方法,可以更好地处理权限受限的目录。
6. 使用 Guava
Guava 也提供了便捷的方法来处理目录遍历:
@Test
public void whenGetFolderSizeUsingGuava_thenCorrect() {
long expectedSize = 12607;
File folder = new File("src/test/resources");
Iterable<File> files = Files.fileTraverser().breadthFirst(folder);
long size = StreamSupport.stream(files.spliterator(), false)
.filter(f -> f.isFile())
.mapToLong(File::length)
.sum();
assertEquals(expectedSize, size);
}
✅ Guava 的 fileTraverser()
方法提供了广度优先的目录遍历能力,配合 Java 8 的 Stream 使用效果很好。
7. 转换为人类可读格式
获取字节大小后,我们通常希望将其转换为更直观的单位(如 KB、MB):
@Test
public void whenGetReadableSize_thenCorrect() {
File folder = new File("src/test/resources");
long size = getFolderSize(folder);
String[] units = new String[] { "B", "KB", "MB", "GB", "TB" };
int unitIndex = (int) (Math.log10(size) / 3);
double unitValue = 1 << (unitIndex * 10);
String readableSize = new DecimalFormat("#,##0.#")
.format(size / unitValue) + " "
+ units[unitIndex];
assertEquals("12.3 KB", readableSize);
}
✅ 使用 DecimalFormat
来控制小数位数,使输出更美观。
8. 注意事项
在处理目录大小时需要注意以下几点:
- 如果安全管理器拒绝访问,
Files.walk()
和Files.walkFileTree()
会抛出SecurityException
- 如果目录中包含符号链接,可能会导致无限循环 ❌
9. 总结
本教程展示了多种获取目录大小的方法,包括:
- Java 原生递归实现
- Java 7 的 NIO.2 API
- Java 8 的 Stream 方式
- Apache Commons IO
- Guava
所有示例代码均可在 GitHub 项目 中找到,这是一个 Maven 项目,可直接导入运行。