Автор оригинала: Adam McQuistan.
- Вступление
- Базовый файл IO в Python
- Чтение Строка за строкой
- Пример Приложения
- Вывод
Вступление
За свою трудовую жизнь я имел возможность использовать множество программных концепций и технологий для выполнения бесчисленных задач. Некоторые из этих вещей включают в себя относительно малоценные плоды моего труда, такие как автоматизация подверженных ошибкам или обыденных процессов, таких как генерация отчетов, автоматизация задач и общее переформатирование данных. Другие были гораздо более ценными, такие как разработка продуктов обработки данных, веб-приложений и конвейеров анализа и обработки данных. Одна вещь, которая примечательна почти во всех этих проектах, – это необходимость просто открыть файл, проанализировать его содержимое и что-то с ним сделать.
Однако что вы делаете, когда файл, который вы пытаетесь использовать, довольно велик? Что делать, если файл содержит несколько ГБ данных или больше? Опять же, это был еще один частый аспект моей карьеры программиста, который в основном проводился в биотехнологическом секторе, где часто встречаются файлы размером 1 ТБ+.
Ответ на эту проблему состоит в том, чтобы читать куски файла за один раз, обрабатывать его, а затем освобождать его из памяти, чтобы вы могли вытащить и обработать другой кусок, пока весь массивный файл не будет обработан. В то время как программист должен определить подходящий размер блока, для многих приложений он подходит для обработки файла по одной строке за раз.
В этой статье мы рассмотрим несколько примеров кода, чтобы показать, как читать файлы построчно. Если вы хотите попробовать некоторые из этих примеров самостоятельно, код, используемый в этой статье, можно найти в следующем репо GitHub .
Базовый файл IO в Python
Будучи отличным языком программирования общего назначения, Python имеет ряд очень полезных функций ввода-вывода файлов в своей стандартной библиотеке встроенных функций и модулей. Встроенная функция open ()
-это то, что вы используете для открытия объекта file для чтения или записи.
fp = open('path/to/file.txt', 'r')
Функция open()
принимает несколько аргументов. Мы сосредоточимся на первых двух, причем первый из них является позиционным строковым параметром, представляющим путь к файлу, который должен быть открыт. Второй необязательный параметр также является строкой, которая определяет режим взаимодействия, предназначенный для объекта file, возвращаемого вызовом функции. Наиболее распространенные режимы перечислены в таблице ниже, причем по умолчанию используется “r” для чтения.
r | Открыт для чтения обычного текста |
w | Открыт для записи обычного текста |
a | Откройте существующий файл для добавления обычного текста |
rb | Открыт для чтения двоичных данных |
всемирный банк | Открыт для записи двоичных данных |
После того как вы записали или прочитали все необходимые данные для объекта file, вам нужно закрыть файл, чтобы ресурсы могли быть перераспределены в операционной системе, в которой выполняется код.
fp.close()
Вы часто увидите много фрагментов кода в Интернете или в программах в дикой природе, которые явно не закрывают файловые объекты, созданные в соответствии с приведенным выше примером. Всегда полезно закрыть ресурс файлового объекта, но многие из нас либо слишком ленивы, либо забывчивы, чтобы сделать это, либо думают, что мы умны, потому что документация предполагает, что открытый файловый объект сам закроется, как только процесс завершится. Это не всегда так.
Вместо того чтобы твердить о том, как важно всегда вызывать close()
для файлового объекта, я хотел бы предложить альтернативный и более элегантный способ открыть файловый объект и убедиться, что интерпретатор Python очистит его после нас:)
with open('path/to/file.txt') as fp: # do stuff with fp
Просто используя ключевое слово with (введенное в Python 2.5) для обертывания нашего кода для открытия файлового объекта, внутренние компоненты Python сделают что-то похожее на следующий код, чтобы гарантировать, что независимо от того, какой файловый объект будет закрыт после использования.
try: fp = open('path/to/file.txt') # do stuff with fp finally: fp.close()
Любой из этих двух методов подходит, причем первый пример является более “питоническим” способом.
Чтение Строка за строкой
Теперь давайте перейдем к фактическому чтению в файле. Объект file, возвращаемый из open ()
, имеет три общих явных метода ( read
, readline
и readlines
) для чтения данных и еще один неявный способ.
Метод read
будет считывать все данные в одну текстовую строку. Это полезно для небольших файлов, где вы хотели бы сделать текстовую манипуляцию со всем файлом или что-то еще, что вам подходит. Тогда есть readline
, который является одним из полезных способов чтения только в отдельных строках инкрементных сумм за один раз и возврата их в виде строк. Последний явный метод, readlines
, прочитает все строки файла и вернет их в виде списка строк.
Как упоминалось ранее, вы можете использовать эти методы только для загрузки небольших фрагментов файла за один раз. Чтобы сделать это с помощью этих методов, вы можете передать им параметр, указывающий, сколько байтов нужно загрузить за один раз. Это единственный аргумент, который принимают эти методы.
Ниже показана одна реализация для чтения текстового файла по одной строке за раз, которая выполняется с помощью метода readline ()
.
Примечание : В оставшейся части этой статьи я буду демонстрировать, как читать в тексте книги “Илиаду Гомера”, которую можно найти по адресу gutenberg.org , а также в репо GitHub, где находится код для этой статьи.
В readline.py вы найдете следующий код. В терминале, если вы запустите $ python readline.py
вы можете увидеть результат чтения всех строк Илиады, а также их номера строк.
filepath = 'Iliad.txt' with open(filepath) as fp: line = fp.readline() cnt = 1 while line: print("Line {}: {}".format(cnt, line.strip())) line = fp.readline() cnt += 1
Приведенный выше фрагмент кода открывает файловый объект , хранящийся в виде переменной с именем fp
, затем читает строку за раз, вызывая readline
на этом файловом объекте итеративно в цикле while
и выводит его на консоль.
Запустив этот код, вы должны увидеть что-то вроде следующего:
$ python forlinein.py Line 0: BOOK I Line 1: Line 2: The quarrel between Agamemnon and Achilles--Achilles withdraws Line 3: from the war, and sends his mother Thetis to ask Jove to help Line 4: the Trojans--Scene between Jove and Juno on Olympus. Line 5: Line 6: Sing, O goddess, the anger of Achilles son of Peleus, that brought Line 7: countless ills upon the Achaeans. Many a brave soul did it send Line 8: hurrying down to Hades, and many a hero did it yield a prey to dogs and Line 9: vultures, for so were the counsels of Jove fulfilled from the day on ...
Хотя это совершенно нормально, есть один последний способ, о котором я мимолетно упоминал ранее, который менее явен, но немного более элегантен, и который я очень предпочитаю. Этот последний способ чтения файла строка за строкой включает в себя итерацию по файловому объекту в цикле for
, присваивая каждой строке специальную переменную с именем line
. Приведенный выше фрагмент кода может быть воспроизведен в следующем коде, который можно найти в скрипте Python forlinein.py:
filepath = 'Iliad.txt' with open(filepath) as fp: for cnt, line in enumerate(fp): print("Line {}: {}".format(cnt, line))
В этой реализации мы используем преимущества встроенной функциональности Python, которая позволяет нам неявно перебирать файловый объект с помощью цикла for
в сочетании с использованием итеративного объекта fp
. Это не только проще читать, но и требует меньше строк кода для написания, что всегда является лучшей практикой, достойной следования.
Пример Приложения
Я был бы неосторожен написать приложение о том, как потреблять информацию в текстовом файле, не продемонстрировав хотя бы тривиальное использование такого достойного навыка. Тем не менее, я продемонстрирую небольшое приложение, которое можно найти в wordcount.py, который вычисляет частоту каждого слова, присутствующего в “Илиаде Гомера”, использованной в предыдущих примерах. Это создает простой набор слов , который обычно используется в приложениях НЛП.
import sys import os def main(): filepath = sys.argv[1] if not os.path.isfile(filepath): print("File path {} does not exist. Exiting...".format(filepath)) sys.exit() bag_of_words = {} with open(filepath) as fp: cnt = 0 for line in fp: print("line {} contents {}".format(cnt, line)) record_word_cnt(line.strip().split(' '), bag_of_words) cnt += 1 sorted_words = order_bag_of_words(bag_of_words, desc=True) print("Most frequent 10 words {}".format(sorted_words[:10])) def order_bag_of_words(bag_of_words, desc=False): words = [(word, cnt) for word, cnt in bag_of_words.items()] return sorted(words, key=lambda x: x[1], reverse=desc) def record_word_cnt(words, bag_of_words): for word in words: if word != '': if word.lower() in bag_of_words: bag_of_words[word.lower()] += 1 else: bag_of_words[word.lower()] = 1 if __name__ == '__main__': main()
Приведенный выше код представляет собой скрипт python командной строки, который ожидает путь к файлу, переданный в качестве аргумента. Скрипт использует модуль os
, чтобы убедиться, что переданный путь к файлу является файлом, существующим на диске. Если путь существует, то каждая строка файла считывается и передается функции с именем record_word_cnt
в виде списка строк, разделенных пробелами между словами, а также словаря с именем bag_of_words
. Функция record_word_cnt
подсчитывает каждый экземпляр каждого слова и записывает его в словарь bag_of_words
.
После того как все строки файла прочитаны и записаны в словарь bag_of_words
, вызывается последний вызов функции order_bag_of_words
, которая возвращает список кортежей в формате (word, word count) , отсортированных по количеству слов. Возвращаемый список кортежей используется для печати наиболее часто встречающихся 10 слов.
Вывод
Итак, в этой статье мы исследовали способы чтения текстового файла построчно двумя способами, включая способ, который, по моему мнению, немного более питонен (это второй способ, продемонстрированный в forlinein.py). В заключение я представил тривиальное приложение, которое потенциально полезно для чтения и предварительной обработки данных, которые могут быть использованы для анализа текста или анализа настроений.
Как всегда, я с нетерпением жду ваших комментариев и надеюсь, что вы сможете использовать то, что было обсуждено, для разработки интересных и полезных приложений.