IPad - Разбор чрезвычайно большого json файла (от 50 до 100 мб)

Я пытаюсь разобрать чрезвычайно большой json файл на iPad. Размер файла будет варьироваться от 50 до 100 мб (есть начальный файл, и каждый месяц будет один новый полный набор данных, который будет загружен, проанализирован и сохранен в coredata).

Я создаю это приложение для компании как решение для предприятия - файл json содержит конфиденциальные данные клиента, и его необходимо сохранить локально на ipad, чтобы он работал даже в автономном режиме. Он работал, когда файл находился ниже 20 МБ, но теперь набор данных стал больше, и мне действительно нужно его разобрать. Во время разбора я получаю предупреждения о памяти, а после третьего предупреждения он просто падает. У меня есть несколько разных объектов Core Data, и я просто устанавливаю все значения, исходящие из json файла (когда приложение запускается в первый раз), и после того, как все сделано, я делаю [context save].

Я надеялся, что кто-нибудь может дать мне несколько советов о том, как обращаться с такими огромными файлами. Я думал о том, чтобы разбить файл json на несколько меньших json файлов и, возможно, проанализировать их в нескольких потоках, но я не знаю, правильно ли это подходит. Я думаю, одна большая проблема в том, что весь файл хранится в памяти - может быть, есть способ "потокового" его в память или что-то в этом роде?

Я использую JSONKit (https://github.com/johnezang/JSONKit) для разбора файла, так как я прочитал, что он самый быстрый (возможно, более медленный, который проще по памяти?).

Спасибо заранее.

Ответ 1

1) Напишите свои данные в файл, затем используйте NSData dataWithContentsOfFile: options: error: и укажите флаги NSDataReadingMappedAlways и NSDataReadingUncached. Это позволит системе использовать mmap() для уменьшения объема памяти, а не для того, чтобы обременять кеш файловой системы блоками памяти (что делает его более медленным, но гораздо меньшим бременем для iOS).

2) Вы можете использовать JSON-анализатор YAJL SAX для получения объектов по мере их декодирования.

Примечание: я не сделал 2), но использовал методы, воплощенные в 1).

3) Я так и сам нуждался в такой вещи и писал SAX-JSON-Parser-ForStreamingData, который может быть привязан к любому асинхронному загрузчику (включая мои собственные).

Ответ 2

Учитывая текущие ограничения памяти на мобильном устройстве, вероятно, невозможно разобрать 100 МБ текста JSON, а затем создать представление объекта Foundation, которое само по себе займет примерно в 10 раз больше ОЗУ, чем размер исходного текста JSON.

То есть, ваш результат JSON займет около 1 ГБ ОЗУ, чтобы выделить пространство, необходимое для объектов фундамента.

Таким образом, нет возможности создать одно гигантское представление JSON - независимо от того, как вы получаете и читаете и разбираете ввод. Вам нужно разбить его на несколько более мелких. Это может потребовать изменения на стороне сервера.

Другое решение - это, но гораздо более подробно:

Используйте синтаксический анализатор SAX, который использует огромный JSON для ввода через API потоковой передачи и выводит несколько меньших текстов JSON (внутренние части). Парсер SAX-стиля может использовать API-интерфейс Blocks (диспетчер lib) для передачи своих результатов - асинхронно меньших JSON в другой парсер JSON. То есть, младшие JSON подаются обычным парсером JSON, который создает представления JSON, которые, в свою очередь, передаются вашим генератором модели CoreData.

Вы даже можете загрузить огромный JSON и проанализировать его одновременно с парсером SAX-стиля, одновременно создавая меньшие JSON и одновременно сохраняя их в Core Data.

Вам нужен парсер JSON с API-интерфейсом SAX, который может анализировать фрагменты входного текста, быстро выполняет и может создавать представление объектов Foundation.

Я знаю только одну библиотеку JSON, у которой есть эта функция, и есть даже примеры, которые могут частично показать, как вы можете выполнить именно это: JPJson on GitHub. Парсер также очень быстрый - на ARM он быстрее, чем JSONKit. Предостережение: его реализация выполняется на С++ и требует нескольких шагов для его установки на машине разработчика. Однако он имеет хорошо документированный API Objective-C.

Хотелось бы добавить, что я автор;) Скоро появится обновление, в котором используются последние компиляторы С++ 11 и библиотеки С++ 11, что приводит к еще более быстрому коду (на 25% быстрее ARM, чем JSONKit и в два раза быстрее, чем NSJSONSerialization).

Чтобы дать вам то же самое о фактах скорости: Парсер может загружать (через Wi-Fi) и анализировать 25 Мбайт данных, содержащих 1000 JSON (по 25 кбайт каждая) за 7 секунд на Wi-Fi 802.11g и 4 секунды на Wi-Fi 802.11n, включая создание и выпуск 1000 представлений на iPad 2.