首页 iOS大文件读取内存问题
文章
取消

iOS大文件读取内存问题

一般小文件加载我们会直接用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 个枚举:

  1. NSDataReadingMappedIfSafe 如果当前可行的话, 使用 文件映射 读取文件. 这样系统会把文件映射进进程的地址空间, 而无需读取整个文件, 解决内存的问题.
  2. NSDataReadingUncached 无需在文件系统进行缓存. 对于一次性读取和丢弃的数据, 此选项可以提高性能.
  3. NSDataReadingMappedAlways 可能的情况下映射文件. 如果两者都设定,则优先使用 NSDataReadingMappedIfSafe.
  4. NSDataReadingMapped = NSDataReadingMappedIfSafe
  5. NSMappedRead = NSDataReadingMapped
  6. NSUncachedRead = NSDataReadingUncached

对比试验:

做个试验

完整读取文件映射 读取的内存情况: 完整读取内存直接爆炸, 而文件映射读取内存方面并未观察出明显变化. 说明内存的问题的确完美的解决的.

本文由作者按照 CC BY 4.0 进行授权