Подтвердить что ты не робот

Эффективное чтение XML файла объемом 800 ГБ в Python 2.7

Я читаю XML файл размером 800 ГБ в python 2.7 и анализирую его с помощью итеративного парсера etree.

В настоящее время я просто использую open('foo.txt') без аргумента буферизации. Я немного смущен, является ли это подход, который я должен принять, или я должен использовать аргумент буферизации или использовать что-то из io, например io.BufferedReader или io.open или io.TextIOBase.

Было бы очень полезно оценить точку в правильном направлении.

4b9b3361

Ответ 1

Стандартная open() функция уже по умолчанию возвращает буферный файл (если он доступен на вашей платформе). Для файловых объектов, которые обычно полностью буферизуются.

Обычно здесь означает, что Python оставляет это для реализации C stdlib; он использует вызов fopen() (wfopen() в Windows для поддержки имен файлов UTF-16), что означает, что выбрана буферизация по умолчанию для файла; на Linux я считаю, что это будет 8kb. Для операции чистого чтения, такой как разбор XML, этот тип буферизации - именно то, что вы хотите.

Разбор XML, выполняемый iterparse, считывает файл в кусках 16384 байт (16kb).

Если вы хотите управлять буферизацией, используйте аргумент ключевого слова buffering:

open('foo.xml', buffering=(2<<16) + 8)  # buffer enough for 8 full parser reads

который переопределит размер буфера по умолчанию (который, как я полагаю, будет соответствовать размеру файла или его кратности). В соответствии с этой статьей увеличение буфера чтения должно помочь, и, используя размер как минимум в 4 раза, ожидаемый размер блока чтения плюс 8 байтов улучшит производительность чтения. В приведенном выше примере я установил его в 8 раз больше размера чтения ElementTree.

Функция io.open() представляет собой новую структуру объектов ввода-вывода Python 3, где I/O был разделен на новую иерархию типов классов на дают вам большую гибкость. Цена больше косвенности, больше слоев для данных, которые нужно пройти, и код Python C больше работает сам, вместо того, чтобы оставить это в ОС.

Вы можете попробовать и посмотреть, будет ли io.open('foo.xml', 'rb', buffering=2<<16) работать лучше. Открытие в режиме rb даст вам io.BufferedReader экземпляр.

Вы не хотите использовать io.TextIOWrapper; базовый парсер expat хочет сырые данные, поскольку он будет декодировать вашу кодировку XML файла. Это только добавит дополнительные накладные расходы; вы получаете этот тип, если вместо этого открываете его в r (textmode).

Использование io.open() может дать вам большую гибкость и более богатый API, но основной объект C файла открывается с помощью open() вместо fopen(), и вся буферизация обрабатывается реализацией Python io.BufferedIOBase.

Ваша проблема будет обрабатывать этот зверь, а не файл читает, я думаю. В любом случае кеш диска будет в значительной степени застрелен при чтении файла 800 ГБ.

Ответ 2

Вы пробовали ленивую функцию?: Lazy Method для чтения большого файла в Python?

это, кажется, уже отвечает на ваш вопрос. Однако я бы подумал об использовании этого метода для записи ваших данных в базу данных, mysql свободен: http://dev.mysql.com/downloads/, NoSQL также свободен и может быть немного более приспособленным к операциям, связанным с записью 800 гб данных или аналогичных сумм: http://www.oracle.com/technetwork/database/nosqldb/downloads/default-495311.html

Ответ 3

Я не пробовал это с такими эпическими файлами xml, но в прошлый раз мне приходилось иметь дело с большими (и относительно простыми) xml файлами, я использовал sax parser.

Он в основном дает вам обратные вызовы для каждого "события" и оставляет его для хранения необходимых вам данных. Вы можете открыть файл с открытым файлом, поэтому вам не нужно его читать сразу.