iOS 储存空间计算

探究一下我们计算app储存空间的大小时和系统设置里的差距

App自身大小差距

系统设置里App的存储空间分为:“App大小”和“文稿与数据”。

iOS 获取App磁盘占用大小的常规方式就是通过官方NSFileManager配合NSDirectoryEnumerator遍历所有文件来计算整体沙盒大小。
而这里的沙盒大小对标的是 系统里的“文稿与数据”,这样我们与系统就先产生了“App大小”的差距了。

目前没有看到有什么代码的方式来获取app安装大小,或许可以通过 archive app后生成 App Thinning Size Report.txt。
在其中app大小硬编码进代码里。

进制差距

我们一般理所当然认为 1GB=1024MB ,通过1024倍数的方式来将B转换为可以阅读的MB或者GB单位。

但是真的是使用1024转换吗?

通过一下代码在真机256GB大小的手机上运行

1
2
3
4
5
- (NSNumber *) totalDiskSpace 
{
NSDictionary *fattributes = [[NSFileManager defaultManager] fileSystemAttributesAtPath:NSHomeDirectory()];
return [fattributes objectForKey:NSFileSystemSize];
}

获取到的大小大约是 256065450244,若以1024计算 256*1024*1024*1024=274877906944 相差了许多。而使用1000来计算则四舍五入刚好是系统显示的256GB。

而通过apple说明-How storage capacity is measured on Apple devices也说明了使用的事10进制来计算。 所以B转换为KB MB GB的时候要以1000来转换

4K对齐

文件实际大小:是指文件自身的实际大小,1B(字节)的文件”文件实际大小”即为1B(字节)

磁盘占用大小:指文件已占用的磁盘空间(即使没有全部被使用,剩余空间不能存放其他文件的数据,“宁缺毋滥”),1B的文件在macOS/iOS系统中”“磁盘占用大小”为4KB。查阅资料发现实际磁盘是按块为单位进行存储的,由于文件的大小 并不一定是块的整数倍,因此最后一个块可能仅被部分占用,而该块剩余的空间将保持未使用的状态(其他文件也不能使用)。

所以1B(字节)的文件磁盘大小是4KB。

那么我们如何在App内计算文件的“磁盘占用大小”呢?通过NSFileManager直接获取的是文件的“文件实际大小”,而计算文件的磁盘占用大小就需要通过磁盘块。

通过标准头文件stat.h的st_blocks[4]可以获取到块的数量,通过 st_blocks * 512字节 可以计算出文件的磁盘占用大小。

之所以块(扇区)大小是512字节[5],这种做法源自较早的磁盘扇区大小标准。这种设计是基于早期磁盘技术的物理限制,尽管现代硬盘的物理扇区大小可能已经增加到了 4096 字节,但 512 字节的逻辑块大小在许多文件系统和操作系统的接口中仍然被保留。扇区是磁盘读写的最小物理单位节[6]。

当进行磁盘操作时,无论是读取还是写入,系统必须至少处理一个完整的扇区。这是因为磁盘的设计不允许单独修改扇区中的一部分数据,而是必须读取整个扇区,进行修改后再整体写回。

实际操作中,我们发现在iOS中文件的st_blocks总是8的倍数(即使文件实际大小只有1字节),说明iOS的文件系统(APFS)层级的最小的块大小定义为4096字节