macOS下调用statfs无法获取完整磁盘容量,原因是什么?
macOS下statfs获取磁盘容量与Finder显示不一致的问题
问题描述
你在macOS应用中尝试获取存储驱动器的容量及可用空间,执行了以下代码:
struct statfs stStg; if(statfs(".", &stStg) == 0) { uint64_t total_sz = stStg.f_bsize * stStg.f_blocks; uint64_t free_sz = stStg.f_bsize * stStg.f_bfree; double fTotal = (double)total_sz / (1024.0 * 1024.0 * 1024.0); double fFree = (double)free_sz / (1024.0 * 1024.0 * 1024.0); printf("%.02f GB (%.01f%% free)", fTotal, 100.0 * fFree / fTotal); }
代码返回结果:
460.43 GB (66.5% free)
但Finder中显示的磁盘容量更大,需要找出问题所在。
问题原因
- 单位换算差异:Finder采用十进制换算(1GB = 1000³字节),而你的代码用的是二进制换算(1GiB = 1024³字节),这是数值差异的直接原因。
- statfs字段的含义局限:
f_blocks统计的是文件系统分配给用户使用的总块数,不包含macOS系统预留的空间(比如APFS的快照、系统备份分区等),而Finder显示的是磁盘的物理总容量。f_bfree是超级用户才能使用的空闲块数,普通用户实际可用的空闲空间应该用f_bavail字段。
修正方案
1. 匹配Finder的单位换算
如果要让数值和Finder显示对齐,把换算基数改成1000,同时替换正确的空闲空间字段:
struct statfs stStg; if(statfs(".", &stStg) == 0) { uint64_t total_sz = stStg.f_bsize * stStg.f_blocks; // 改用f_bavail获取普通用户可用空间 uint64_t free_sz = stStg.f_bsize * stStg.f_bavail; // 十进制GB换算 double fTotal = (double)total_sz / (1000.0 * 1000.0 * 1000.0); double fFree = (double)free_sz / (1000.0 * 1000.0 * 1000.0); printf("%.02f GB (%.01f%% free)", fTotal, 100.0 * fFree / fTotal); }
2. 获取磁盘物理总容量的方法
如果需要获取和Finder完全一致的物理总容量,statfs无法直接做到,建议使用Apple提供的更高阶API:
Objective-C示例(NSFileManager)
NSURL *rootURL = [NSURL fileURLWithPath:@"/"]; NSArray *keys = @[NSURLVolumeTotalCapacityKey, NSURLVolumeAvailableCapacityForImportantUsageKey]; NSError *error = nil; NSDictionary *volumeAttrs = [rootURL resourceValuesForKeys:keys error:&error]; if (!error) { uint64_t totalCapacity = [volumeAttrs[NSURLVolumeTotalCapacityKey] unsignedLongLongValue]; uint64_t availableCapacity = [volumeAttrs[NSURLVolumeAvailableCapacityForImportantUsageKey] unsignedLongLongValue]; double totalGB = (double)totalCapacity / (1000.0 * 1000.0 * 1000.0); double availableGB = (double)availableCapacity / (1000.0 * 1000.0 * 1000.0); NSLog(@"%.02f GB (%.01f%% free)", totalGB, 100.0 * availableGB / totalGB); }
Swift示例
let rootURL = URL(fileURLWithPath: "/") do { let attrs = try rootURL.resourceValues(forKeys: [.volumeTotalCapacityKey, .volumeAvailableCapacityForImportantUsageKey]) if let total = attrs.volumeTotalCapacity, let available = attrs.volumeAvailableCapacityForImportantUsage { let totalGB = Double(total) / (1000 * 1000 * 1000) let availableGB = Double(available) / (1000 * 1000 * 1000) print(String(format: "%.02f GB (%.01f%% free)", totalGB, 100.0 * availableGB / totalGB)) } } catch { print("获取磁盘信息失败:\(error)") }
内容的提问来源于stack exchange,提问作者c00000fd
相关产品推荐
相关产品推荐

