如何在Java中获取目录在磁盘上的实际占用空间(Linux环境)
如何在Java中获取目录在磁盘上的实际占用空间(Linux环境)
这个问题我之前处理小文件密集的目录时也踩过坑!确实FileUtils.sizeOf()只是简单累加所有文件的逻辑字节大小,完全没考虑磁盘的块分配机制——哪怕是1字节的小文件,也会占用至少一个磁盘块,再加上目录本身的存储开销,结果和du命令的真实占用差几十上百倍太正常了。
下面给你两种可行的解决方案:
方案一:直接调用Linux的du命令(推荐)
既然是Linux环境,直接用系统原生的du命令是最省心也最准确的选择,它会自动处理块大小、目录条目、inode开销这些细节。我们可以通过Java的ProcessBuilder来执行命令并解析结果:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class DiskUsageCalculator { public static long getActualDirectorySize(String dirPath) throws IOException { // 使用du -sb命令:-s汇总目录总大小,-b按字节输出结果 ProcessBuilder processBuilder = new ProcessBuilder("du", "-sb", dirPath); Process process = processBuilder.start(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { String outputLine = reader.readLine(); if (outputLine != null) { // 输出格式是"大小 路径",分割后取第一个数字 return Long.parseLong(outputLine.split("\\s+")[0]); } } finally { process.destroy(); } return -1; // 读取失败返回-1 } public static void main(String[] args) throws IOException { long size = getActualDirectorySize("/path/to/your/directory"); System.out.println("实际占用空间:" + size + " 字节"); } }
这个方法的优点是:完全适配Linux文件系统的特性,结果和du命令完全一致,代码量少不用自己造轮子;唯一的小缺点是依赖系统命令,跨平台性差,但你已经明确是Linux环境,这点可以忽略。
方案二:纯Java实现(手动计算块占用)
如果不想依赖系统命令,也可以自己通过Java NIO API来计算。核心思路是:
- 获取文件系统的块大小
- 遍历所有文件和目录,计算每个文件实际占用的块数(逻辑大小向上取整到块大小的倍数)
- 加上目录本身的实际占用空间
代码示例如下:
import java.io.IOException; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; public class PureJavaDiskUsage { public static long calculateActualSize(Path directory) throws IOException { FileStore fileStore = Files.getFileStore(directory); long blockSize = fileStore.getBlockSize(); // 获取磁盘块大小 long totalSize = 0; // 遍历目录下所有文件和子目录 Files.walkFileTree(directory, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { long fileLogicalSize = attrs.size(); // 计算实际占用的块数:向上取整 long occupiedBlocks = (fileLogicalSize + blockSize - 1) / blockSize; totalSize += occupiedBlocks * blockSize; return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { if (exc == null) { // 计算目录本身的实际占用空间 BasicFileAttributes dirAttrs = Files.readAttributes(dir, BasicFileAttributes.class); long dirLogicalSize = dirAttrs.size(); long occupiedBlocks = (dirLogicalSize + blockSize - 1) / blockSize; totalSize += occupiedBlocks * blockSize; } return FileVisitResult.CONTINUE; } }); return totalSize; } public static void main(String[] args) throws IOException { Path dirPath = Paths.get("/path/to/your/directory"); long actualSize = calculateActualSize(dirPath); System.out.println("实际占用空间:" + actualSize + " 字节"); } }
不过要注意,这个纯Java实现可能和du的结果有细微差异——因为有些文件系统的inode、扩展属性等额外开销,Java API可能无法完全覆盖,所以如果追求绝对准确,还是优先用方案一。
备注:内容来源于stack exchange,提问作者chris01
相关产品推荐
相关产品推荐

