- Обработка больших файлов с использованием Python
- Файлы в python, ввод-вывод
- Файлы Python
- Текстовые файлы
- Бинарные файлы
- Открытие файла
- Метод open()
- Пример
- Закрытие файла
- Метод close()
- Инструкция with
- Чтение и запись файлов в Python
- Функция read()
- Функция readline()
- Функция write()
- Переименование файлов в Python
- Функция rename()
- Текущая позиция в файлах Python
- Вычисление размера каталога с помощью Python?
- 24 ответов
- Использование памяти в Python
- Сколько памяти занимает 1 миллион целых чисел?
- Необходимые инструменты
- Что в итоге?
- Как проверить размер файла в python?
- 9 ответов
Обработка больших файлов с использованием Python
В последний год или около того, и с моим повышенным вниманием к данным ribo-seq я полностью осознал, что означает термин большие данные. Исследования ribo-seq в их необработанном виде могут легко охватить сотни ГБ, что означает, что их обработка как своевременной, так и эффективной требует некоторого обдумывания. В этом посте, и, надеюсь, в следующем, я хочу подробно описать некоторые из методов, которые я придумала (собрал из разных статей в интернете), которые помогают мне получать данные такого масштаба. В частности, я буду подробно описывать методы для Python, хотя некоторые методы можно перенести на другие языки.
Мой первый большой совет по Python о том, как разбить ваши файлы на более мелкие блоки (или куски) таким образом, чтобы вы могли использовать несколько процессоров. Давайте начнем с самого простого способа чтения файла на python.
Эта ошибка, сделанная выше в отношении больших данных, заключается в том, что она считывает все данные в ОЗУ, прежде чем пытаться обрабатывать их построчно. Это, вероятно, самый простой способ вызвать переполнение памяти и возникновение ошибки. Давайте исправим это, читая данные построчно, чтобы в любой момент времени в оперативной памяти сохранялась только одна строка.
Это большое улучшение, и именно оно не перегружает ОЗУ при загрузке большого файла. Затем мы должны попытаться немного ускорить это, используя все эти бездействующие ядра.
При условии, что порядок обработки строк не имеет значения, приведенный выше код генерирует набор (пул) обработчиков, в идеале один для каждого ядра, перед созданием группы задач (заданий), по одной для каждой строки. Я склонен использовать объект Pool, предоставляемый модулем multiprocessing, из-за простоты использования, однако, вы можете порождать и контролировать отдельные обработчики, используя mp.Process, если вы хотите более точное управление. Для простого вычисления числа объект Pool очень хорош.
Хотя вышеперечисленное теперь использует все эти ядра, к сожалению, снова возникают проблемы с памятью. Мы специально используем функцию apply_async, чтобы пул не блокировался во время обработки каждой строки. Однако при этом все данные снова считываются в память; это время сохраняется в виде отдельных строк, связанных с каждым заданием, ожидая обработки в строке. Таким образом, память снова будет переполнена. В идеале метод считывает строку в память только тогда, когда подходит ее очередь на обработку.
Используя поиск, мы можем перейти непосредственно к правильной части файла, после чего мы читаем строку в память и обрабатываем ее. Мы должны быть осторожны, чтобы правильно обрабатывать первую и последнюю строки, но в противном случае это будет именно то, что мы излагаем, а именно использование всех ядер для обработки данного файла без переполнения памяти.
Я закончу этот пост с небольшим обновлением вышеупомянутого, поскольку есть разумные накладные расходы, связанные с открытием и закрытием файла для каждой отдельной строки. Если мы обрабатываем несколько строк файла за один раз, мы можем сократить эти операции. Самая большая техническая сложность при этом заключается в том, что при переходе к месту в файле вы, скорее всего, не находитесь в начале строки. Для простого файла, как в этом примере, это просто означает, что вам нужно вызвать readline, который читает следующий символ новой строки. Более сложные типы файлов, вероятно, требуют дополнительного кода, чтобы найти подходящее место для начала / конца чанка.
Во всяком случае, я надеюсь, что некоторые из вышеперечисленных примеров были новыми и возможно, полезными для вас. Если вы знаете лучший способ сделать что-то (на python), мне было бы очень интересно узнать об этом. В следующем посте, который будет опубликован в ближайшем будущем, я расширю этот код, превратив его в родительский класс, из которого создается несколько дочерних элементов для использования с различными типами файлов.
Файлы в python, ввод-вывод
Эта статья посвящена работе с файлами (вводу/выводу) в Python: открытие, чтение, запись, закрытие и другие операции.
Файлы Python
Файл — это всего лишь набор данных, сохраненный в виде последовательности битов на компьютере. Информация хранится в куче данных (структура данных) и имеет название «имя файла» (filename).
В Python существует два типа файлов:
Текстовые файлы
Это файлы с человекочитаемым содержимым. В них хранятся последовательности символов, которые понимает человек. Блокнот и другие стандартные редакторы умеют читать и редактировать этот тип файлов.
Бинарные файлы
В бинарных файлах данные отображаются в закодированной форме (с использованием только нулей (0) и единиц (1) вместо простых символов). В большинстве случаев это просто последовательности битов.
Любую операцию с файлом можно разбить на три крупных этапа:
Открытие файла
Метод open()
Пример
Создадим текстовый файл example.txt и сохраним его в рабочей директории.
Следующий код используется для его открытия.
Следующий код используется для вывода содержимого файла и информации о нем.
Закрытие файла
Метод close()
После открытия файла в Python его нужно закрыть. Таким образом освобождаются ресурсы и убирается мусор. Python автоматически закрывает файл, когда объект присваивается другому файлу.
Существуют следующие способы:
Способ №1
После закрытия этот файл нельзя будет использовать до тех пор, пока заново его не открыть.
Способ №2
Без него программа завершается некорректно.
Вот как сделать это исключение:
Этот метод гарантирует, что если операции над файлом вызовут исключения, то он закроется до того как программа остановится.
Способ №3
Инструкция with
В таком случае инструкция close не нужна, потому что with автоматически закроет файл.
Вот как это реализовать в коде.
Чтение и запись файлов в Python
В Python файлы можно читать или записывать информацию в них с помощью соответствующих режимов.
Функция read()
Функция read() используется для чтения содержимого файла после открытия его в режиме чтения ( r ).
Синтаксис
Пример
Функция readline()
Функция readline() используется для построчного чтения содержимого файла. Она используется для крупных файлов. С ее помощью можно получать доступ к любой строке в любой момент.
Пример
Создадим файл test.txt с нескольким строками:
Обратите внимание, как в последнем случае строки отделены друг от друга.
Функция write()
Функция write() используется для записи в файлы Python, открытые в режиме записи.
Если пытаться открыть файл, которого не существует, в этом режиме, тогда будет создан новый.
Синтаксис
Пример
Предположим, файла xyz.txt не существует. Он будет создан при попытке открыть его в режиме чтения.
Переименование файлов в Python
Функция rename()
Функция rename() используется для переименовывания файлов в Python. Для ее использования сперва нужно импортировать модуль os.
Пример
Текущая позиция в файлах Python
Вычисление размера каталога с помощью Python?
прежде чем я заново изобрету это конкретное колесо, у кого-нибудь есть хорошая процедура для вычисления размера каталога с помощью Python? Было бы очень хорошо, если бы процедура отформатировала размер красиво в Mb/Gb и т. д.
24 ответов
это бросается в подкаталоги:
и oneliner для удовольствия с помощью os.listdir (не включает подкаталоги):
Обновлено Использовать os.путь.getsize не, это яснее, чем использование ОС.stat ().st_size метод.
спасибо ghostdog74 за указание на это!
обновить 2018
если вы используете Python 3.4 или предыдущий, вы можете использовать более эффективный walk метод, предоставленный третьей стороной scandir пакета. В Python 3.5 и позже этот пакет был включен в стандартную библиотеку и os.walk получил соответствующее увеличение производительности.
некоторые из предложенных до сих пор подходов реализуют рекурсию, другие используют оболочку или не будут производить аккуратно отформатированные результаты. Когда ваш код является одноразовым для платформ Linux,вы можете получить форматирование как обычно, включая рекурсию, в виде однострочного. За исключением print в последней строке, он будет работать на текущей версии python2 и python3 :
просто, эффективно и будет работать для файлов и многоуровневых каталогов:
немного поздно через 5 лет, но поскольку это все еще находится в хитлистах поисковых систем, это может помочь.
Использование памяти в Python
Сколько памяти занимает 1 миллион целых чисел?
Меня часто донимали размышление о том, насколько эффективно Python использует память по сравнению с другими языками программирования. Например, сколько памяти нужно, чтобы работать с 1 миллионом целых чисел? А с тем же количеством строк произвольной длины?
Как оказалось, в Python есть возможность получить необходимую информацию прямо из интерактивной консоли, не обращаясь к исходному коду на C (хотя, для верности, мы туда все таки заглянем).
Удовлетворив любопытство, мы залезем внутрь типов данных и узнаем, на что именно расходуется память.
Все примеры были сделаны в CPython версии 2.7.4 на 32 битной машине. В конце приведена таблица для потребности в памяти на 64 битной машине.
Необходимые инструменты
sys.getsizeof и метод __sizeof__()
Первый инструмент, который нам потребуется находится в стандартной библиотеки sys. Цитируем официальную документацию:
Возвращает размер объекта в байтах.
Если указано значение по умолчанию, то оно вернется, если объект не предоставляет способа получить размер. В противном случае возникнет исключение TypeError.
Getsizeof() вызывает метод объекта __sizeof__ и добавляет размер дополнительной информации, которая хранится для сборщика мусора, если он используется.
Алгоритм работы getsizeof(), переписанной на Python, мог бы выглядеть следующем образом:
Где PyGC_Head — элемент двойного связанного списка, который используется сборщиком мусора для обнаружения кольцевых ссылок. В исходном коде он представлен следующей структурой:
Размер PyGC_Head будет равен 12 байт на 32 битной и 24 байта на 64 битной машине.
Попробуем вызвать getsizeof() в консоли и посмотрим, что получится:
За исключением магии с проверкой флагов, все очень просто.
Как видно из примера, int и float занимают 12 и 16 байт соответственно. Str занимает 21 байт и еще по одному байту на каждый символ содержимого. Пустой кортеж занимает 12 байт, и дополнительно 4 байта на каждый элемент. Для простых типов данных (которые не содержат ссылок на другие объекты, и соответственно, не отслеживаются сборщиком мусора), значение sys.getsizeof равно значению, возвращаемого методом __sizeof__().
id() и ctypes.string_at
Теперь выясним, на что именно расходуется память.
Для этого нужно нам нужны две вещи: во-первых, узнать, где именно хранится объект, а во-вторых, получить прямой доступ на чтение из памяти. Несмотря на то, что Python тщательно оберегает нас от прямого обращения к памяти, это сделать все таки возможно. При этом нужно быть осторожным, так как это может привести к ошибке сегментирования.
Встроенная функция id() возвращает адрес памяти, где храниться начала объекта (сам объект является C структурой)
Чтобы считать данные по адресу памяти нужно воспользоваться функцией string_at из модуля ctypes. Ее официальное описание не очень подробное:
ctypes.string_at(адрес[, длина])
Это функция возвращает строку, с началом в ячейки памяти «адрес». Если «длина» не указана, то считается что строка zero-terminated,
Теперь попробуем считать данные по адресу, который вернул нам id():
Вид шестнадцатеричного кода не очень впечатляет, но мы близки к истине.
Модель Struct
Для того чтобы представить вывод в значения, удобные для восприятия, воспользуемся еще одним модулем. Здесь нам поможет функция unpack() из модуля struct.
struct
Этот модуль производит преобразование между значениями Python и структурами на C, представленными в виде строк.
struct.unpack(формат, строка)
Разбирает строку в соответствие с данным форматов. Всегда возвращает кортеж, даже если строка содержит только один элемент. Строка должна содержать в точности то количество информации, как описано форматом.
Форматы данных, которые нам потребуются.
символ | Значение C | Значение Python | Длина на 32битной машине |
c | char | Строка из одного символа | 1 |
i | int | int | 4 |
l | long | int | 4 |
L | unsigned long | int | 4 |
d | double | float | 8 |
Теперь собираем все вместе и посмотрим на внутреннее устройство некоторых типов данных.
О формате значений несложно догадаться.
Первое число (373) — количество указателей, на объект.
Как видно, число увеличилось на единицу, после того как мы создали еще одну ссылку на объект.
Второе число (136770080) — указатель (id) на тип объекта:
Третье число (1) — непосредственно содержимое объекта.
Наши догадки можно подтвердить, заглянув в исходный код CPython
Здесь PyObject_HEAD — макрос, общий для всех встроенных объектов, а ob_ival — значение типа long. Макрос PyObject_HEAD добавляет счетчик количества указателей на объект и указатель на родительский тип объекта — как раз то, что мы и видели.
Float
Число с плавающей запятой очень похоже на int, но представлено в памяти C значением типа double.
В этом легко убедиться:
Строка (Str)
Строка представлена в виде массива символов, оканчивающимся нулевым байтом. Также в структуре строки отдельного сохраняется ее длина, хэш от ее содержания и флаг, определяющий, хранится ли она во внутреннем кэше interned.
Макрос PyObject_VAR_HEAD включает в себя PyObject_HEAD и добавляет значение long ob_ival, в котором хранится длина строки.
Четвертое значение соответствует хэшу от строки, в чем нетрудно убедиться.
Как видно, значение sstate равно 0, так что строка сейчас не кэшируется. Попробуем ее добавить в кэш:
Кортеж (Tuple)
Кортеж представлен в виде массива из указателей. Так как его использование может приводить к возникновению кольцевых ссылок, он отслеживается сборщиком мусора, на что расходуется дополнительная память (об этом нам напоминает вызов sys.getsizeof())
Структура tuple похоже на строку, только в ней отсутствуют специальные поля, кроме длины.
Как видим из примера, последние три элементы кортежа являются указателями на его содержимое.
Остальные базовые типы данных (unicode, list, dict, set, frozenset) можно исследовать аналогичным образом.
Что в итоге?
Тип | Имя в CPython | формат | Формат, для вложенных объектов | Длина на 32bit | Длина на 64bit | Память для GC* |
Int | PyIntObject | LLl | 12 | 24 | ||
float | PyFloatObject | LLd | 16 | 24 | ||
str | PyStringObject | LLLli+c*(длина+1) | 21+длина | 37+длина | ||
unicode | PyUnicodeObject | LLLLlL | L*(длина+1) | 28+4*длина | 52+4*длина | |
tuple | PyTupleObject | LLL+L*длина | 12+4*длина | 24+8*длина | Есть | |
list | PyListObject | L*5 | L*длину | 20+4*длина | 40+8*длина | Есть |
Set/ frozenset | PySetObject | L*7+(lL)*8+lL | LL* длина | ( 5 элементов) 100+8*длина | ( 5 элементов) 200+16*длина | Есть |
dict | PyDictObject | L*7+(lLL)*8 | lLL*длина | ( 5 элементов) 124+12*длина | ( 5 элементов) 248+24*длина | Есть |
* Добавляет 12 байт на 32 битной машине и 32 байта на 64 битной машине
Мы видим, что простые типы данных в Python в два-три раза больше своих прототипов на C. Разница обусловлена необходимостью хранить количество ссылок на объект и указатель на его тип (содержимое макроса PyObject_HEAD). Частично это компенсируется внутренним кэшированием, который позволяет повторно использовать ранее созданные объекты (это возможно только для неизменяемых типов).
Для строк и кортежей разница не такая значительная — добавляется некоторая постоянная величина.
А списки, словари и множества, как правило, занимают больше на 1/3, чем необходимо. Это обусловлено реализацией алгоритма добавления новых элементов, который приносит в жертву память ради экономии времени процессора.
Итак, отвечаем на вопрос в начале статьи: чтобы сохранить 1 миллион целых чисел нам потребуется 11.4 мегабайт (12*10^6 байт) на сами числа и дополнительно 3.8 мегабайт (12 + 4 + 4*10^6 байт) на кортеж, которых будет хранить на них ссылки.
UPD: Опечатки.
UPD: В подзаголовке «1 миллион целых чисел», вместо «1 миллион простых чисел»
Как проверить размер файла в python?
Я пишу Python script в Windows. Я хочу сделать что-то на основе размера файла. Например, если размер больше 0, я пришлю электронное письмо кому-либо, в противном случае продолжаю другие вещи.
Как проверить размер файла?
9 ответов
538 Решение Adam Rosenfield [2010-01-20 22:01:00]
Используйте os.stat и используйте элемент st_size результирующего объекта:
Вывод находится в байтах.
869 danben [2010-01-20 21:59:00]
Вывод находится в байтах.
Другие ответы работают на реальные файлы, но если вам нужно что-то, что работает для «файловых объектов», попробуйте следующее:
Edit
Другое отличие между этим и os.stat() заключается в том, что вы можете stat() файл, даже если у вас нет разрешения на его чтение. Очевидно, что подход seek/tell не будет работать, если у вас нет разрешения на чтение.
Изменить 2
В предположении Джонатона, здесь параноидальная версия. (Версия выше оставляет указатель файла в конце файла, поэтому, если вы попытаетесь прочитать из файла, вы получите нулевые байты!)
14 pumazi [2016-11-17 20:23:00]
Использование pathlib (добавлено в Python 3.4 и доступно на PyPI).
Пример: 5GB are 5368709120 bytes
Строго придерживаясь вопроса, код python (+ псевдо-код) будет выглядеть следующим образом:
вы можете получить размер файла в октетах, как показано ниже: