16

我正在尝试在 iPad 上解析一个非常大的 json 文件。文件大小将在 50 到 100 mb 之间变化(有一个初始文件,每个月都会有一个新的完整数据集,将被下载、解析并保存到 coredata 中)

我正在为一家公司构建这个应用程序作为企业解决方案 - json 文件包含敏感的客户数据,它需要本地保存在 ipad 上,这样它甚至可以离线工作。当文件低于 20mb 时它可以工作,但现在数据集变得更大,我真的需要解析它。我在解析过程中收到内存警告,在第三次警告之后它就崩溃了。我有几个不同的核心数据实体,我只是设置来自 json 文件的所有值(当应用程序第一次启动时),一切都完成后,我正在做[context save].

我希望有人能给我一些关于如何处理如此大的文件的建议。我正在考虑将 json 文件拆分为几个较小的 json 文件,并可能在多个线程中解析它们,但我不知道这是否是正确的方法。我想一个大问题是整个文件都保存在内存中 - 也许有某种方式可以将它“流式传输”到内存中或类似的东西?

我正在使用 JSONKit ( https://github.com/johnezang/JSONKit ) 来解析文件,因为我已经读过它是最快的(也许有一个较慢的更容易记忆?)。

提前致谢。

4

2 回答 2

21

1) 将数据写入文件,然后使用 NSData 的dataWithContentsOfFile:options:error:并指定NSDataReadingMappedAlwaysNSDataReadingUncached标志。这将告诉系统使用 mmap() 来减少内存占用,而不是用内存块给文件系统缓存增加负担(这会使其速度变慢,但对 iOS 的负担要小得多)。

2) 您可以使用YAJL SAX 样式的 JSON 解析器在对象解码时获取它们。

注意:我没有做过 2),但使用了 1) 中体现的技术。

3) 我自己最终需要这样的东西,并编写了可以绑定到任何异步下载器(包括我自己的)的 SAX-JSON-Parser-ForStreamingData 。

于 2013-04-10T17:51:59.400 回答
3

鉴于移动设备上当前的内存限制,可能无法解析 100 MB JSON 文本然后创建Foundation 对象的表示,该对象本身将占用大约 10 倍于源 JSON 文本大小的 RAM 量。

也就是说,您的 JSON 结果需要大约 1 GB 的 RAM 才能分配基础对象所需的空间。

因此,无论您如何获取、读取和解析输入,都可能无法创建一个巨大的 JSON 表示。你需要把它分成许多更小的。不过,这可能需要在服务器端进行修改。

另一个解决方案是这样,但更详细:

使用 SAX 样式解析器,它通过流式 API 将巨大的 JSON 作为输入,并输出几个较小的 JSON 文本(内部部分)。SAX 样式解析器可以使用 Blocks API(调度库)来传递其结果 - 较小的 JSON 异步传递给另一个 JSON 解析器。也就是说,较小的 JSON 会被提供给生成 JSON 表示的常用 JSON 解析器,而后者又会被提供给您的 CoreData 模型生成器。

您甚至可以下载巨大的 JSON 并使用 SAX 样式解析器同时解析它,同时创建更小的 JSON 并将它们同时存储到 Core Data 中。

您需要的是一个带有 SAX 风格 API 的 JSON 解析器,它可以解析输入文本块,执行速度很快,并且可以创建 Foundation 对象的表示。

我只知道一个 JSON 库具有此功能集,甚至给出的示例可以部分展示您如何准确地完成此操作:GitHub 上的 JPJson。解析器也非常快——在 ARM 上它比 JSONKit 更快。警告:它的实现是用 C++ 实现的,需要几个步骤才能将其安装在开发人员机器上。不过,它有一个有据可查的 Objective-C API。

想补充一下,我是作者 ;) 很快就会有一个更新,它利用最新的 C++11 编译器和 C++11 库功能,从而产生更快的代码(在 ARM 上比 JSONKit 快 25% 和两倍快作为 NSJSONSerialization)。

为您提供与速度相同的事实:解析器能够在 Wifi 802.11g 上 7 秒和 Wifi 802.11n 上 4 秒内下载(通过 WiFi)并解析包含 1000 个 JSON(每个 25 kByte)的 25 MB 数据,包括在 iPad 2 上创建和发布 1000 个表示。

于 2013-04-11T17:13:55.980 回答