一般小文件加载我们会直接用API
加载完整的文件来进行处理:
1
NSData *data = [NSData dataWithContentsOfFile:@"..."]
但是遇到比较大的文件, 比如 100MB
甚至是 1GB
的文件, 还使用这种方法来加载, 内存肯定要爆炸…
一开始想到的方法是: 在 iOS 下能否有办法每次仅仅加载文件的某一段数据来进行处理. 就像 HTTP 请求头部的 Range 字段一样, 来获取文件数据的一部分
. 但是实际上 iOS 有提供更好的解决办法
查阅文档后发现 NSData 提供有 2 个这样的方法:
1
2
3
+ (instancetype)dataWithContentsOfFile:(NSString *)path options:(NSDataReadingOptions)readOptionsMask error:(NSError **)errorPtr;
+ (instancetype)dataWithContentsOfURL:(NSURL *)url options:(NSDataReadingOptions)readOptionsMask error:(NSError **)errorPtr;
此处最关键的是 readOptionsMask
这个参数.
NSDataReadingOptions
类型包含 6 个枚举:
NSDataReadingMappedIfSafe
如果当前可行的话, 使用 文件映射 读取文件. 这样系统会把文件映射进进程的地址空间, 而无需读取整个文件, 解决内存的问题.NSDataReadingUncached
无需在文件系统进行缓存. 对于一次性读取和丢弃的数据, 此选项可以提高性能.NSDataReadingMappedAlways
可能的情况下映射文件. 如果两者都设定,则优先使用NSDataReadingMappedIfSafe
.NSDataReadingMapped
=NSDataReadingMappedIfSafe
NSMappedRead
=NSDataReadingMapped
NSUncachedRead
=NSDataReadingUncached
对比试验:
用 完整读取
和 文件映射
读取的内存情况: 完整读取内存直接爆炸, 而文件映射读取内存方面并未观察出明显变化. 说明内存的问题的确完美的解决的.