Работа с файлами

На практике в реальных проектах Data Science часто приходится сталкиваться с чтением датасетов, а также записывать добытую в ходе вычислений информацию в файлы. Сегодня мы расскажем о работе с файлами в Python: чтение и запись, проблема с кодировками, добавление значений в конец файла, временные папки и файлы.

Открываем, а затем читаем или записываем

Предположим, у нас имеется файл, который нужно прочитать в Python. Для этого можно воспользоваться функцией open внутри контекстного менеджера:

with open('file.txt') as f:
    data = f.read() # содержимое файла

Таким же образом можно записать информацию в файл, указав w в качестве аргумента:

text = 'Hello'
with open('file.txt', 'w') as f:
    f.write(text)

Отметим некоторые особенности данной функции. Во-первых, для чтения файла мы не указывали никаких аргументов кроме имени файла, поскольку по умолчанию уже стоит режим чтения. Мы также не указывали явно, что это именно текстовый файл, а не бинарный, так как это тоже стоит по умолчанию. Для чтения и записи бинарных файлов добавляется b, например, rb или wb.

Во-вторых, мы использовали функцию open в контекстном менеджере. Можно обойтись и без него, но тогда после чтения или записи следует закрыть файл.

f = open('file.txt')
f.read()
f.close()

На открытие файла Python выделяет память, поэтому, чтобы избежать ее утечки, рекомендуется закрывать файлы.

Чтение файла с разной кодировкой

На многих операционных системах Python в качестве стандарта кодирования использует UTF-8, который также поддерживает кириллицу. Тем не менее, часто можно столкнуться с проблемами неправильной кодировки и получить распространенную ошибку вроде этой:

>>> f = open('somefile.txt', encoding='ascii')
>>> f.read()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/Python3.8/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position
12: ordinal not in range(128))

В примере указана кодировка ASCII, но файл закодирован в другом формате, поэтому и возникает такая ошибка. Решить ее можно тремя способами:

  1. Указать erorr=replace, который заменит нераспознанные символы знаком ?:
    >>> f = open('somefile.txt', encoding='ascii', errors='replace')
    >>> f.read()
    'H?llo py?ho?-school!'
    
  2. Указать erorr=ignore, который проигнорирует нераспознанные символы:
    >>> f = open('somefile.txt', encoding='ascii', errors='replace')
    >>> f.read()
    'Hllo pyho-school!'
    
  3. Указать правильную кодировку. Если текст на русском языке, то можно посмотреть кодировки с поддержкой кириллицы, которые есть в документации Python. Например, явно указать UTF-8 или cp1251:
    f = open('somefile.txt', encoding='utf-8')
    # или cp1251
    f = open('somefile.txt', encoding='cp1251')
    

Добавление в конец и запрет открытия файлов

Как мы уже отметили ранее, для записи текстового файла добавляется аргумент w. Но если вызвать метод write, он перепишет весь файл. Во многих случаях требуется добавить данные в конец файла. Тогда используется a вместо w:

text2 = 'world'
with open('file.txt', 'a') as f:
    f.write(text)
# Helloworld

Если файла не существует, то при a и при w он будет создан. Но чтобы не трогать существующие файлы, а создать новый, передается параметр x:

# 'x' не даст возможности открыть файл, так как он существует
>>> with open('file.txt', 'x') as f:
...    f.write(text2)
FileExistsError                           Traceback (most recent call last)

  FileExistsError: [Errno 17] File exists: 'file.txt'

# Поскольку file2.txt не существует, все OK
>>> with open('file2.txt', 'x') as f:
...    f.write(text2)

Временные файлы

Иногда бывает, что требуется создать файл или папку внутри Python-программы, а после ее закрытия их нужно удалить. Тогда пригодится стандартный модуль tempfile. Например, класс TemporaryFile создаст временный файл, который удалится после закрытия. Ниже пример в Python.

>>> from tempfile import TemporaryFile
>>> f = TemporaryFile("w+t")
>>> f.write("hello")
>>> f.seek(0)
>>> f.read()
'hello'
>>> f.close() # файл уничтожается
# либо в контекстном менеджере
    f.write(text2)

Обратите внимание на 3 вещи. Первое, мы явно передаем "w+t", чтобы записать как текстовый файл, поскольку по умолчанию стоит "w+b" для бинарных файлов. Второе, метод seek(0) используется для перехода на самый первый символ, поскольку чтение происходит с текущего указателя, а он стоит в конце (после буквы ‘o’ в слове ‘hello’). Поэтому не стоит переживать, что мы можем стереть предыдущую запись:

>>> f.seek(5) # переходим в конец
>>> f.read()
''
>>> f.write("world")
5
>>> f.seek(0) # переходим в начало
>>> f.read()
'helloworld'

Третье, файл TemporaryFile невидим для файловой системы, он используется только внутри Python, поэтому извне будет трудно его найти.

Именованные временные файлы

А вот объекты класса NamedTemporaryFile будут видны файловой системе, и найти месторасположение можно с помощью атрибута name:

>>> from tempfile import NamedTemporaryFile
>>> f = NamedTemporaryFile("w+t")
>>> f.name
'/tmp/tmp60djsgli'
>>> f.close()

Как можно заметить, файл называется tmp60djsgli. Для удобства можно явно указать его название и формат:

>>> f = NamedTemporaryFile("w+t", prefix="myfile", suffix=".txt")
>>> f.name
'/tmp/myfile7mxae0fi.txt'

Временные папки

Кроме временных файлов можно создавать временные папки. Для этого используется класс TemporaryDirectory:

>>> from tempfile import TemporaryDirectory
>>> d = TemporaryDirectory()
>>> d.name
'/tmp/tmp5eadqzz5'

Он также принимает в качестве аргументов prefix и suffix, а также может использоваться внутри контекстного менеджера Python.

 

В следующей статье поговорим о взаимодействии файловой системы и Python. А получить практические навыки работы с файлами на реальных проектах Data Science вы сможете на наших курсах по Python в лицензированном учебном центре обучения и повышения квалификации IT-специалистов в Москве.

Источники
  1. https://docs.python.org/3/library/functions.html#open
  2. https://docs.python.org/3/library/tempfile.html

Добавить комментарий

Поиск по сайту