Python становится все популярнее благодаря относительной простоте изучения, универсальности и другим преимуществам. Правда, у начинающих разработчиков нередко возникают проблемы при работе с файлами и файловой системой. Просто потому, что они знают не все команды, которые нужно знать.
Эта статья предназначена как раз для начинающих разработчиков. В ней описаны 8 крайне важных команд для работы с файлами, папками и файловой системой в целом. Все примеры из этой статьи размещены в Google Colab Notebook (ссылка на ресурс — в конце статьи).
Показать текущий каталог
Самая простая и вместе с тем одна из самых важных команд для Python-разработчика. Она нужна потому, что чаще всего разработчики имеют дело с относительными путями. Но в некоторых случаях важно знать, где мы находимся.
Относительный путь хорош тем, что работает для всех пользователей, с любыми системами, количеством дисков и так далее.
Так вот, для того чтобы показать текущий каталог, нужна встроенная в Python OS-библиотека:
import os
os.getcwd()
Ее легко запомнить, так что лучше выучить один раз, чем постоянно гуглить. Это здорово экономит время.
Имейте в виду, что я использую Google Colab, так что путь /content является абсолютным.
Проверяем, существует файл или каталог
Прежде чем задействовать команду по созданию файла или каталога, стоит убедиться, что аналогичных элементов нет. Это поможет избежать ряда ошибок при работе приложения, включая перезапись существующих элементов с данными.
Функция os.path.exists () принимает аргумент строкового типа, который может быть либо именем каталога, либо файлом.
В случае с Google Colab при каждом запуске создается папка sample_data. Давайте проверим, существует ли такой каталог. Для этого подойдет следующий код:
os.path.exists('sample_data')
Эта же команда подходит и для работы с файлами:
os.path.exists(‘sample_data/README.md’)
Если папки или файла нет, команда возвращает false.
Объединение компонентов пути
В предыдущем примере я намеренно использовал слеш «/» для разделителя компонентов пути. В принципе это нормально, но не рекомендуется. Если вы хотите, чтобы ваше приложение было кроссплатформенным, такой вариант не подходит. Так, некоторые старые версии ОС Windows распознают только слеш «\» в качестве разделителя.
Но не переживайте, Python прекрасно решает эту проблему благодаря функции os.path.join (). Давайте перепишем вариант из примера в предыдущем пункте, используя эту функцию:
os.path.exists(os.path.join('sample_data', 'README.md'))
Создание директории
Ну а теперь самое время создать директорию с именем test_dir внутри рабочей директории. Для этого можно использовать функцию
os.mkdir():
os.mkdir('test_dir')
Давайте посмотрим, как это работает на практике.
Если же мы попытаемся создать каталог, который уже существует, то получим исключение.
Именно поэтому рекомендуется всегда проверять наличие каталога с определенным названием перед созданием нового:
if not os.path.exists('test_dir'):
os.mkdir('test_dir')
Еще один совет по созданию каталогов. Иногда нам нужно создать подкаталоги с уровнем вложенности 2 или более. Если мы все еще используем os.mkdir (), нам нужно будет сделать это несколько раз. В этом случае мы можем использовать os.makedirs (). Эта функция создаст все промежуточные каталоги так же, как флаг mkdir -p в системе Linux:
os.makedirs(os.path.join('test_dir', 'level_1', 'level_2', 'level_3'))
Вот что получается в результате.
Показываем содержимое директории
Еще одна полезная команда — os.listdir(). Она показывает все содержимое каталога.
Команда отличается от os.walk (), где последний рекурсивно показывает все, что находится «под» каталогом. os.listdir () намного проще в использовании, потому что просто возвращает список содержимого:
os.listdir('sample_data')
В некоторых случаях нужно что-то более продвинутое — например, поиск всех CSV-файлов в каталоге «sample_data». В этом случае самый простой способ — использовать встроенную библиотеку glob:
from glob import globlist(glob(os.path.join('sample_data', '*.csv')))
Перемещение файлов
Самое время попробовать переместить файлы из одной папки в другую. Рекомендованный способ — еще одна встроенная библиотека shutil.
Сейчас попробуем переместить все CSV-файлы из директории «sample_data» в директорию «test_dir». Ниже — пример кода для выполнения этой операции:
import shutilfor file in list(glob(os.path.join('sample_data', '*.csv'))):
shutil.move(file, 'test_dir')
Кстати, есть два способа выполнить задуманное. Например, мы можем использовать библиотеку OS, если не хочется импортировать дополнительные библиотеки. Как os.rename, так и os.replace подходят для решения задачи.
Но обе они недостаточно «умные», чтобы позволить перемесить файлы в каталог.
Чтобы все это работало, нужно явно указать имя файла в месте назначения. Ниже — код, который это позволяет сделать:
for file in list(glob(os.path.join('test_dir', '*.csv'))):
os.rename(
file,
os.path.join(
'sample_data',
os.path.basename(file)
))
Здесь функция os.path.basename () предназначена для извлечения имени файла из пути с любым количеством компонентов.
Другая функция, os.replace (), делает то же самое. Но разница в том, что os.replace () не зависит от платформы, тогда как os.rename () будет работать только в системе Unix / Linux.
Еще один минус — в том, что обе функции не поддерживают перемещение файлов из разных файловых систем, в отличие от shutil.
Поэтому я рекомендую использовать shutil.move () для перемещения файлов.
Копирование файлов
Аналогичным образом shutil подходит и для копирования файлов по уже упомянутым причинам.
Если нужно скопировать файл README.md из папки «sample_data» в папку «test_dir», поможет функция shutil.copy():
shutil.copy(
os.path.join('sample_data', 'README.md'),
os.path.join('test_dir')
)
Удаление файлов и папок
Теперь пришел черед разобраться с процедурой удаления файлов и папок. Нам здесь снова поможет библиотека OS.
Когда нужно удалить файл, нужно воспользоваться командой os.remove():
os.remove(os.path.join('test_dir', 'README(1).md'))
Если требуется удалить каталог, на помощь приходит os.rmdir():
os.rmdir(os.path.join('test_dir', 'level_1', 'level_2', 'level_3'))
Однако он может удалить только пустой каталог. На приведенном выше скриншоте видим, что удалить можно лишь каталог level_3. Что если мы хотим рекурсивно удалить каталог level_1? В этом случае зовем на помощь shutil.
Функция shutil.rmtree() сделает все, что нужно:
shutil.rmtree(os.path.join('test_dir', 'level_1'))
Пользоваться ею нужно с осторожностью, поскольку она безвозвратно удаляет все содержимое каталога.
Собственно, на этом все. 8 важных операций по работе с файлами и каталогами в среде Python мы знаем. Что касается ссылки, о которой говорилось в анонсе, то вот она — это Google Colab Network с содержимым, готовым к запуску.
Для работы с файловой системой в Python используют модули
os, os.path и shututil, а для операций с файлами – встроенные функции open(), close(), read(), readline(), write() и т. д. Прежде, чем мы перейдем
к примерам использования конкретных методов, отметим один важный момент – корректный формат пути к файлам и каталогам.
Дело в том, что Python считает некорректным стандартный
для Windows формат: если указать путь к файлу в привычном виде 'C:\Users\User\Python\letters.py'
, интерпретатор вернет ошибку. Лучше
всего указывать путь с помощью r-строк
или с экранированием слэшей:
r'C:\Users\User\Python\letters.py'
'C:\\Users\\User\\Python\\letters.py'
Иногда также путь указывают с обратными слэшами:
'C:/Users/User/Python/letters.py'
🐍🎓 Библиотека собеса по Python
🐍🧩 Библиотека задач по Python
Получение информации о файлах и директориях
Метод getcwd() возвращает
путь к текущей рабочей директории в виде строки:
>>> import os
>>> os.getcwd()
'C:\\Users\\User\\Python'
С помощью метода os.listdir() можно получить список всех поддиректорий и файлов текущего рабочего каталога, при этом содержимое вложенных папок не отображается:
>>> os.listdir()
['Data', 'lambda_functions.py', 'letters.py', 'os_methods.py', 'passw_generator.py', 'points.py', 'population.py']
Метод os.walk() возвращает генератор, в котором содержится
вся информация о рабочем каталоге, включая содержимое всех поддиректорий:
>>> import os
>>> my_cwd = os.getcwd()
>>> result = os.walk(my_cwd)
>>> for i, j, k in result:
for file in k:
print(file)
lambda_functions.py
letters.py
os_methods.py
passw_generator.py
points.py
population.py
books_to_process.txt
challenge_data.txt
ledger.txt
Много полезных методов содержится в модуле os.path. Так можно извлечь имя файла из полного пути:
>>> os.path.basename(r'C:\Users\User\Python\letters.py')
'letters.py'
А так можно получить путь к директории / файлу, в который не
включается собственно поддиректория или имя файла:
>>> os.path.dirname(r'C:\Users\User\Python\Data')
'C:\\Users\\User\\Python'
Метод path.isabs() покажет, является ли
путь абсолютным или относительным:
>>> os.path.isabs(r'C:\Users\User\Python\Data')
True
>>> os.path.isabs(r'.\Python\Data')
False
>>>
Метод path.isdir() возвращает True
, если переданная в метод директория существует, и False
– в противном случае:
>>> os.path.isdir(r'C:\Users\User\Python\Data\Samples')
False
Для установления факта существования файла служит path.isfile():
>>> os.path.isfile(r'C:\Users\User\Python\matrix_challenge.py')
False
Для преобразования пути в нижний регистр и нормализации слэшей используют path.normcase():
>>> os.path.normcase('C:/Users/User/Python')
'c:\\users\\user\\python'
Хотя путь к файлу (директории) представляет собой строку,
создавать полный путь с помощью конкатенации считается моветоном – нужно
использовать метод os.path.join():
# Неправильно:
my_cwd = os.getcwd()
file_name = 'my_solution.py'
path = my_cwd + '\\' + file_name
# Правильно:
path = os.path.join(my_cwd, file_name)
Результат:
C:\Users\User\Python\my_solution.py
Операции с каталогами и файлами в Python
Для создания новых директорий служит os.mkdir(); в метод нужно передать полный путь, включающий название
нового каталога:
import os
my_cwd = os.getcwd()
new_dir = 'Solutions'
path = os.path.join(my_cwd, new_dir)
os.mkdir(path)
print(os.listdir())
Результат:
['Data', 'lambda_functions.py', 'letters.py', 'os_methods.py', 'passw_generator.py', 'points.py', 'population.py', 'Solutions']
Изменить рабочую директорию можно с помощью метода os.chdir(), это аналог CLI команды cd
:
>>> import os
>>> os.getcwd()
'C:\\Users\\User\\Python'
>>> os.chdir(r'C:\Users\User\Python\Data')
>>> os.getcwd()
'C:\\Users\\User\\Python\\Data'
Использование os.chdir()
может привести к ошибке, если путь к переданной в метод директории указан
неправильно или не существует. Поэтому этот метод стоит использовать только с
обработкой ошибок:
import sys, os
my_cwd = os.getcwd()
new_cwd = r'C:\Users\User\Python\MyData'
try:
os.chdir(new_cwd)
print(f'Изменяем рабочую директорию на {os.getcwd()}')
except:
print(f'Произошла ошибка {sys.exc_info()}')
finally:
print('Восстанавливаем рабочую директорию на прежнюю')
os.chdir(my_cwd)
print(f'Текущая рабочая директория - {os.getcwd()}')
Вывод:
Произошла ошибка (<class 'FileNotFoundError'>, FileNotFoundError(2, 'Не удается найти указанный файл'), <traceback object at 0x024E9828>)
Восстанавливаем рабочую директорию на прежнюю
Текущая рабочая директория - C:\Users\User\Python
Python для новичков: бессрочный доступ к знаниям и поддержка экспертов
Онлайн-курс «Основы программирования на Python» от Proglib academy предлагает 32 практических урока с персональной обратной связью от экспертов, где вы создадите 4 реальных проекта для портфолио и получите все необходимые навыки для старта карьеры в IT.
Создание директорий в Python
Для создания новых каталогов используют два метода:
- os.mkdir() – аналог CLI команды
mkdir
; создает новую папку по указанному пути, при условии, что все указанные промежуточные (вложенные) директории уже существуют. - os.makedirs() – аналог CLI команды
mkdir -p dir1\dir2
; помимо создания целевой папки, создает все промежуточные директории, если они не существуют.
Пример использования os.mkdir():
import os
new_dir = 'NewProjects'
parent_dir = r 'C:\Users\User\Python'
path = os.path.join(parent_dir, new_dir)
os.mkdir(path)
print(f'Директория {new_dir} создана: {os.listdir()}')
Результат:
Директория NewProjects создана: ['Data', 'lambda_functions.py', 'letters.py', 'NewProjects', 'os_methods.py', 'Other', 'passw_generator.py', 'points.py', 'population.py', 'Solutions']
Пример использования makedirs():
import os
new_dir = 'Django'
parent_dir = r'C:\Users\User\Python\Other\Projects\Modules'
path = os.path.join(parent_dir, new_dir)
os.makedirs(path)
print(f'Директория {new_dir} создана по адресу {os.path.dirname(path)}')
Результат:
Директория Django создана по адресу C:\Users\User\Python\Other\Projects\Modules
Копирование файлов и директорий в Python
Для копирования файлов используют метод shutil.copy2(), который принимает два аргумента
– источник файла и директорию, в которую нужно скопировать файл:
import os
import shutil
dest_path = r'C:\Users\User\Python\Data'
source_path = r'C:\Users\User\lambda_exp.txt'
print(f'Файлы в директории {os.path.basename(dest_path)} до копирования файла \
{os.path.basename(source_path)}: {os.listdir(dest_path)}\n')
copy_file = shutil.copy2(source_path, dest_path)
print(f'Файлы в директории {os.path.basename(dest_path)} после копирования файла \
{os.path.basename(source_path)}: {os.listdir(dest_path)}')
Вывод:
Файлы в директории Data до копирования файла lambda_exp.txt: ['books_to_process.txt', 'challenge_data.txt', 'ledger.txt']
Файлы в директории Data после копирования файла lambda_exp.txt: ['books_to_process.txt', 'challenge_data.txt', 'lambda_exp.txt', 'ledger.txt']
Помимо метода shutil.copy2(),
для копирования файлов можно пользоваться методом shutil.copy(). Разница между
этими двумя методами в том, что в отличие от shutil.copy2(),
метод shutil.copy() копирует только
содержимое файла, но не метаданные:
import os
import shutil
dest_path = r'C:\Users\User\Python\Data'
source_path = r'C:\Users\User\logfile.txt'
print(f'Файлы в директории {os.path.basename(dest_path)} до копирования файла \
{os.path.basename(source_path)}: {os.listdir(dest_path)}\n')
print(f'Метаданные: {os.stat(source_path)}\n')
copy_file = shutil.copy(source_path, dest_path)
print(f'Файлы в директории {os.path.basename(dest_path)} после копирования файла \
{os.path.basename(source_path)}: {os.listdir(dest_path)}\n')
print(f'Метаданные: {os.stat(dest_path)}\n')
Вывод:
Файлы в директории Data до копирования файла logfile.txt: ['books_to_process.txt', 'challenge_data.txt', 'lambda_exp.txt']
Метаданные: os.stat_result(st_mode=33206, st_ino=18014398509552989, st_dev=4236505663, st_nlink=1, st_uid=0, st_gid=0, st_size=455, st_atime=1629682315, st_mtime=1629681887, st_ctime=1629682315)
Файлы в директории Data после копирования файла logfile.txt: ['books_to_process.txt', 'challenge_data.txt', 'lambda_exp.txt', 'logfile.txt']
Метаданные: os.stat_result(st_mode=16895, st_ino=11821949021901021, st_dev=4236505663, st_nlink=1, st_uid=0, st_gid=0, st_size=0, st_atime=1675257729, st_mtime=1675257729, st_ctime=1675084801)
Все содержимое каталога сразу можно скопировать с помощью shutil.copytree():
import os
import shutil
dest_path = r'C:\Users\User\Python\Other\Files'
source_path = r'C:\Users\User\Python\Other\Scripts'
print(f'Содержимое директории {os.path.basename(dest_path)} до копирования каталога \
{os.path.basename(source_path)}: {os.listdir(dest_path)}\n')
copy_dir = shutil.copytree(source_path, dest_path, dirs_exist_ok=True)
print(f'Содержимое директории {os.path.basename(dest_path)} после копирования \
{os.path.basename(source_path)}: {os.listdir(dest_path)}\n')
Вывод:
Содержимое директории Files до копирования каталога Scripts: []
Содержимое директории Files после копирования Scripts: ['progression.py', 'sitemap_generator.py']
Перемещение файлов и директорий
Для перемещения файлов используют метод shutil.move():
import os
import shutil
dest_path = r'C:\Users\User\Python\Other\Scripts'
source_path = r'C:\Users\User\Desktop\sitemap_generator.py'
print(f'Содержимое директории {os.path.basename(dest_path)} до копирования каталога \
{os.path.basename(source_path)}: {os.listdir(dest_path)}\n')
copy_dir = shutil.move(source_path, dest_path)
print(f'Содержимое директории {os.path.basename(dest_path)} после копирования \
{os.path.basename(source_path)}: {os.listdir(dest_path)}\n')
Вывод:
Содержимое директории Scripts до копирования каталога sitemap_generator.py: ['progression.py', 'wiki_scraping.py']
Содержимое директории Scripts после копирования sitemap_generator.py: ['progression.py', 'sitemap_generator.py', 'wiki_scraping.py']
Для перемещения содержимого всей директории в качестве
функции указывают shutil.copytree():
copy_dir = shutil.move(source_path, dest_path, copy_function = shutil.copytree)
Удаление файлов и директорий
Для удаления директории вместе со всеми файлами используют shutil.rmtree():
import os
import shutil
dir_path = r'C:\Users\User\Python\Other'
remove_dir = 'Files'
path = os.path.join(dir_path, remove_dir)
print(f'Содержимое директории {os.path.basename(dir_path)} до удаления каталога \
{remove_dir}: {os.listdir(dir_path)}\n')
shutil.rmtree(path)
print(f'Содержимое директории {os.path.basename(dir_path)} после удаления \
{remove_dir}: {os.listdir(dir_path)}\n')
Вывод:
Содержимое директории Other до удаления каталога Files: ['Files', 'Projects']
Содержимое директории Other после удаления Files: ['Projects']
Другой метод для удаления пустых директорий – os.rmdir():
import os
import shutil
dir_path = r'C:\Users\User\Python\Other'
remove_dir = 'Scripts'
path = os.path.join(dir_path, remove_dir)
print(f'Содержимое директории {os.path.basename(dir_path)} до удаления каталога \
{remove_dir}: {os.listdir(dir_path)}\n')
os.rmdir(path)
print(f'Содержимое директории {os.path.basename(dir_path)} после удаления \
{remove_dir}: {os.listdir(dir_path)}\n')
Вывод:
Содержимое директории Other до удаления каталога Scripts: ['Projects', 'Scripts']
Содержимое директории Other после удаления Scripts: ['Projects']
Очевидный минус метода os.rmdir()
в том, что он работает только на пустых директориях – если поместить в каталог Scripts хотя бы один файл,
удалить его с os.rmdir() уже не получится:
Traceback (most recent call last):
File "C:\Users\User\Python\os_methods.py", line 8, in <module>
os.rmdir(path)
OSError: [WinError 145] Папка не пуста: 'C:\\Users\\User\\Python\\Other\\Scripts'
Для удаления файлов используют метод os.remove():
import os
import shutil
dir_path = r'C:\Users\User\Python\Other\Scripts'
remove_file = 'tetris_game.py'
path = os.path.join(dir_path, remove_file)
print(f'Содержимое директории {os.path.basename(dir_path)} до удаления файла \
{remove_file}: {os.listdir(dir_path)}\n')
os.remove(path)
print(f'Содержимое директории {os.path.basename(dir_path)} после удаления \
{remove_file}: {os.listdir(dir_path)}\n')
Вывод:
Содержимое директории Scripts до удаления файла tetris_game.py: ['tetris_game.py']
Содержимое директории Scripts после удаления tetris_game.py: []
Работа с файлами в Python
Открыть файл для проведения каких-либо манипуляций можно
двумя способами:
- С помощью функции open() – в этом случае после завершения работы нужно будет закрыть файл с помощью close():
f = open('task.txt', 'a', encoding='utf-8')
f.write('\n2) Написать модуль авторизации')
f.close()
- С использованием менеджера контекста with, который автоматически и самостоятельно закроет файл, когда надобность в нем отпадет:
with open('task.txt', 'a', encoding='utf-8') as f:
f.write('\n2) Написать модуль авторизации')
Типы файлов
В Python все файлы делятся на:
- Текстовые
't'
- Бинарные (двоичные)
'b'
Если никакой определенный тип файла не указан, по умолчанию Python считает, что пользователь работает с текстовыми файлами. Поэтому для работы с изображениями, мультимедийными файлами и pdf, например, следует указывать, что тип файла относится к 'b'
.
Режимы доступа и записи
‘r’ | Открывает файл для чтения. Возвращает ошибку, если указанный файл не существует. |
‘w’ | Открывает файл для записи, причем перезаписывает содержимое, если оно есть. Создает файл, если он не существует. |
‘a’ | Открывает файл для записи и добавляет новую информацию, не перезаписывая существующую. Создает файл, если он не существует. |
‘w+’ | Открывает файл для чтения и записи, перезаписывает содержимое. |
‘r+’ | Открывает файл для чтения и дополнения, не перезаписывает содержимое. |
‘x’ | Создает новый пустой файл. Возвращает ошибку, если файл с таким именем уже существует. |
Примечание: для операций с двоичными файлами к указанным
параметрам нужно добавлять b
,
то есть вместо 'r'
должно быть 'rb'
, а
вместо 'w+'
– 'wb+'
.
Методы работы с файлами
Для чтения данных используют read(). Метод read() по умолчанию возвращает все содержимое файла:
with open('books.txt', 'r', encoding='utf-8') as f:
info = f.read()
print(info)
Вывод:
1. "Террор", Дэн Симмонс
2. "Она же Грейс", Маргарет Этвуд
3. "Облачный атлас", Дэвид Митчелл
4. "Искупление", Иэн Макьюэн
5. "Госпожа Бовари", Гюстав Флобер
При необходимости объем выводимой информации можно ограничить
определенным количеством символов:
with open('movies.txt', 'r', encoding='utf-8') as f:
info = f.read(15)
print(info)
Вывод:
1. "Из машины"
Метод readline()
позволяет считывать информацию из текстовых файлов построчно:
with open('books.txt', 'r', encoding='utf-8') as f:
info = f.readline()
print(info)
Вывод:
1. "Террор", Дэн Симмонс
Для получения всех строк файла используют метод readlines(),
который возвращает содержимое в виде списка – вместе со всеми спецсимволами:
with open('books.txt', 'r', encoding='utf-8') as f:
info = f.readlines()
print(info)
Вывод:
['1. "Террор", Дэн Симмонс\n', '2. "Она же Грейс", Маргарет Этвуд\n', '3. "Облачный атлас", Дэвид Митчелл\n', '4. "Искупление", Иэн Макьюэн\n', '5. "Госпожа Бовари", Гюстав Флобер']
Чтобы избавиться от лишних пробелов, символа новой строки (и любых других
спецсимволов), используют методы rstrip(), lstrip()
или strip():
with open('books.txt', 'r', encoding='utf-8-sig') as f:
info = [line.strip() for line in f.readlines()]
print(info)
Вывод:
['1. "Террор", Дэн Симмонс', '2. "Она же Грейс", Маргарет Этвуд', '3. "Облачный атлас", Дэвид Митчелл', '4. "Искупление", Иэн Макьюэн', '5. "Госпожа Бовари", Гюстав Флобер']
Для записи информации в файл используют метод write():
with open('books.txt', 'a', encoding='utf-8') as f:
f.write('\n6. "Война и мир", Лев Толстой\n')
Или writelines():
with open('books.txt', 'a', encoding='utf-8') as f:
f.writelines(['7. "Преступление и наказание", Федор Достоевский\n',
'8. "Мизери", Стивен Кинг\n',
'9. "Джейн Эйр", Шарлотта Бронте\n'])
Кроме того, записывать данные в файл можно с помощью print():
with open('crm_log.txt', 'a', encoding='utf-8') as file:
print('\nСергей Леонов, 11:18, 12:23', file=file)
Чтобы узнать текущую позицию курсора в файле, используют метод tell():
with open('books.txt', 'r', encoding='utf-8-sig') as f:
f.readline()
f.read(5)
print(f.tell())
Вывод:
51
Для считывания данных из определенной позиции используют seek():
with open('movies.txt', 'r', encoding='utf-8') as f:
f.seek(53)
print(f.read())
Вывод:
3. "Дракула Брэма Стокера"
Практика
Задание 1
Имеется файл books.txt, содержащий следующую
информацию:
1. "Террор", Дэн Симмонс
2. "Она же Грейс", Маргарет Этвуд
3. "Облачный атлас", Дэвид Митчелл
4. "Искупление", Иэн Макьюэн
5. "Госпожа Бовари", Гюстав Флобер
6. "Война и мир", Лев Толстой
7. "Преступление и наказание", Федор Достоевский
8. "Мизери", Стивен Кинг
9. "Джейн Эйр", Шарлотта Бронте
Напишите программу, которая выводит первые 3 строки файла.
Решение:
with open('books.txt', 'r', encoding='utf-8') as file:
for i in range(3):
line = file.readline().strip()
print(line)
Задание 2
Напишите программу, которая получает от пользователя имя
файла и возвращает следующие данные о его содержимом:
- количество строк;
- количество слов;
- число символов без пробелов и точек.
Пример ввода:
series.txt
Содержимое файла:
1. Последнее королевство 2015
2. Рим 2005
3. Версаль 2015
4. Тюдоры 2007
5. Террор 2018
6. Человек в высоком замке 2015
7. Белая королева 2013
8. Братья по оружию 2001
9. Медичи 2016
10. Спартак 2010
Вывод:
Количество строк в файле series.txt: 10
Количество слов: 17
Число символов: 153
Решение:
filename = input()
lines, words, symbols = 0, 0, 0
with open(filename, 'r', encoding='utf-8') as file:
for i in file:
lines += 1
words += len([w for w in i.split() if w.isalpha()])
symbols += len([s for s in i if s.isalnum()])
print(f'Количество строк в файле {filename}: {lines}\n'
f'Количество слов: {words}\n'
f'Число символов: {symbols}\n'
)
Задание 3
Напишите программу, которая находит самое длинное слово в
списке книг из первого задания.
Ожидаемый результат:
Преступление
Решение:
with open('books.txt', 'r', encoding='utf-8') as file:
words = file.read().replace('"', '').split()
result = [w for w in words if len(w) == len(max(words, key=len))]
print(*result)
Задание 4
Имеется файл fruit.txt со
следующим содержимым:
Апельсин маракуйя папайя айва Яблоко
апельсин яблоко ананас банан персик Слива
Банан груша слива виноград авокадо Цитрон
Слива Груша яблоко мандарин цитрон
лимон Лайм апельсин ананас персик айва
Хурма киви хурма манго авокадо лайм
Нектарин Инжир гранат Папайя Гранат
Напишите программу, которая подсчитывает, сколько раз
название каждого фрукта встречается в тексте.
Вывод:
Названия этих фруктов встречаются в тексте:
"апельсин" - 3 раз(а)
"маракуйя" - 1 раз(а)
"папайя" - 2 раз(а)
"айва" - 2 раз(а)
"яблоко" - 3 раз(а)
"ананас" - 2 раз(а)
"банан" - 2 раз(а)
"персик" - 2 раз(а)
"слива" - 3 раз(а)
"груша" - 2 раз(а)
"виноград" - 1 раз(а)
"авокадо" - 2 раз(а)
"цитрон" - 2 раз(а)
"мандарин" - 1 раз(а)
"лимон" - 1 раз(а)
"лайм" - 2 раз(а)
"хурма" - 2 раз(а)
"киви" - 1 раз(а)
"манго" - 1 раз(а)
"нектарин" - 1 раз(а)
"инжир" - 1 раз(а)
"гранат" - 2 раз(а)
Решение:
with open('fruit.txt', 'r', encoding='utf-8') as file:
result = {}
for line in file:
words = line.strip().lower().split()
for w in words:
result[w] = result.get(w, 0) + 1
print(f'Названия этих фруктов встречаются в тексте:')
for k, v in result.items():
print(f'"{k}" - {v} раз(а)'
Задание 5
Имеются два файла, first.txt и second.txt. В первом файле
перечислены имена, во втором – должности:
Содержимое файла first.txt
Сергей Ковалев
Ирина Егорова
Никита Степанов
Марина Арефьева
Кирилл Евстегнеев
Елена Моисеева
Файл second.txt
мидл разработчик
девопс
тимлид
сеньор разработчик
продакт-менеджер
дизайнер
Напишите программу, которая открывает оба файла и выводит
сведения о сотрудниках в следующем формате:
Сотрудник Сергей Ковалев, должность - мидл разработчик
Сотрудник Ирина Егорова, должность - девопс
Сотрудник Никита Степанов, должность - тимлид
Сотрудник Марина Арефьева, должность - сеньор разработчик
Сотрудник Кирилл Евстегнеев, должность - продакт-менеджер
Сотрудник Елена Моисеева, должность – дизайнер
Решение:
with open('first.txt', 'r', encoding='utf-8') as file1, \
open('second.txt', 'r', encoding='utf-8') as file2:
for line_x, line_y in zip(file1, file2):
print(f'Сотрудник {line_x.strip()}, должность - {line_y.strip()}')
Задание 6
Напишите программу, которая:
- генерирует коды букв русского алфавита от а до я;
- вставляет в полученный список код ё;
- записывает полный алфавит (строчный и прописной варианты каждой буквы) в столбик в файл alphabet.txt.
Содержимое файла после выполнения программы:
Аа
Бб
Вв
Гг
Дд
Ее
Ёё
Жж
Зз
Ии
Йй
Кк
Лл
Мм
Нн
Оо
Пп
Рр
Сс
Тт
Уу
Фф
Хх
Цц
Чч
Шш
Щщ
Ъъ
Ыы
Ьь
Ээ
Юю
Яя
Решение:
alpha = [i for i in range(ord('а'), ord('я') + 1)]
alpha.insert(6, 1105)
with open('alphabet.txt', 'w', encoding='utf-8') as file:
for i in alpha:
file.write(chr(i).upper() + chr(i) + '\n')
Задание 7
Сведения о доходах и расходах компании хранятся в двух
файлах, income.txt и
outcome.txt. Напишите программу для
подсчета прибыли компании.
Пример файла income.txt:
RUB100000
RUB200000
RUB200000
RUB500000
RUB600000
RUB100000
RUB700000
Пример файла outcome.txt:
-RUB1000
-RUB2000
-RUB50000
-RUB200000
-RUB10000
-RUB5000
-RUB6000
-RUB10000
-RUB19000
-RUB7000
Ожидаемый результат:
Прибыль за прошлый месяц: 2090000 RUB
Решение:
income, outcome = 0, 0
with open('income.txt', 'r', encoding='utf-8') as file1, \
open('outcome.txt', 'r', encoding='utf-8') as file2:
for line in file1:
num = line.strip()[3:]
income += int(num)
for line in file2:
num = line.strip()[4:]
outcome += int(num)
print(f'Прибыль за прошлый месяц: {income - outcome} RUB')
Задание 8
Напишите программу, которая считывает сведения об
успеваемости по основным предметам из файла grades.txt,
и определяет, кто из студентов имеет средний балл >= 4.5.
Пример файла grades.txt:
Арефьева И. 5 5 4 4
Богданов С. 5 5 3 4
Гаврилов Е. 4 4 3 3
Егорова А. 3 3 3 4
Семенова Е. 4 3 3 4
Хворостов И. 5 4 5 5
Ожидаемый результат:
Арефьева И., средний балл: 4.50
Хворостов И., средний балл: 4.75
Решение:
result = {}
with open('grades.txt', 'r', encoding='utf-8') as file1:
for line in file1:
l = line.strip().split()
grades = [int(i) for i in l[-4:]]
aver_grade = sum(grades) / len(grades)
if aver_grade >= 4.5:
result[l[0] + ' ' + l[1]] = aver_grade
for student, aver_grade in result.items():
print(f'{student}, средний балл: {aver_grade:.2f}')
Задание 9
Напишите программу, которая получает от пользователя
название файла с информацией на русском языке, и выполняет транслитерацию
текста в соответствии с приведенным ниже словарем. Результат нужно записать в
файл result.txt.
Словарь:
translit = {'а': 'a', 'к': 'k', 'х': 'h', 'б': 'b', 'л': 'l', 'ц': 'c', 'в': 'v', 'м': 'm', 'ч': 'ch', 'г': 'g', 'н': 'n',
'ш': 'sh', 'д': 'd', 'о': 'o', 'щ': 'shh', 'е': 'e', 'п': 'p', 'ъ': '*', 'ё': 'jo', 'р': 'r', 'ы': 'y', 'ж': 'zh',
'с': 's', 'ь': "'", 'з': 'z', 'т': 't', 'э': 'je', 'и': 'i', 'у': 'u', 'ю': 'ju', 'й': 'j', 'ф': 'f', 'я': 'ya',
'А': 'A', 'К': 'K', 'Х': 'H', 'Б': 'B', 'Л': 'L', 'Ц': 'C', 'В': 'V', 'М': 'M', 'Ч': 'Ch', 'Г': 'G', 'Н': 'N',
'Ш': 'Sh', 'Д': 'D', 'О': 'O', 'Щ': 'Shh', 'Е': 'E', 'П': 'P', 'Ъ': '*', 'Ё': 'Jo', 'Р': 'R', 'Ы': 'Y', 'Ж': 'Zh',
'С': 'S', 'Ь': "'", 'З': 'Z', 'Т': 'T', 'Э': 'Je', 'И': 'I', 'У': 'U', 'Ю': 'Ju', 'Й': 'J', 'Ф': 'F', 'Я': 'Ya'}
Пример русского текста:
Python — это язык программирования, который широко используется в интернет-приложениях, разработке программного обеспечения, науке о данных и машинном обучении (ML). Разработчики используют Python, потому что он эффективен, прост в изучении и работает на разных платформах.
Ожидаемое содержимое result.txt:
Python — jeto yazyk programmirovaniya, kotoryj shiroko ispol'zuetsya v internet-prilozheniyah, razrabotke programmnogo obespecheniya, nauke o dannyh i mashinnom obuchenii (ML). Razrabotchiki ispol'zujut Python, potomu chto on jeffektiven, prost v izuchenii i rabotaet na raznyh platformah.
Решение:
translit = {'а': 'a', 'к': 'k', 'х': 'h', 'б': 'b', 'л': 'l', 'ц': 'c', 'в': 'v', 'м': 'm', 'ч': 'ch', 'г': 'g', 'н': 'n',
'ш': 'sh', 'д': 'd', 'о': 'o', 'щ': 'shh', 'е': 'e', 'п': 'p', 'ъ': '*', 'ё': 'jo', 'р': 'r', 'ы': 'y', 'ж': 'zh',
'с': 's', 'ь': "'", 'з': 'z', 'т': 't', 'э': 'je', 'и': 'i', 'у': 'u', 'ю': 'ju', 'й': 'j', 'ф': 'f', 'я': 'ya',
'А': 'A', 'К': 'K', 'Х': 'H', 'Б': 'B', 'Л': 'L', 'Ц': 'C', 'В': 'V', 'М': 'M', 'Ч': 'Ch', 'Г': 'G', 'Н': 'N',
'Ш': 'Sh', 'Д': 'D', 'О': 'O', 'Щ': 'Shh', 'Е': 'E', 'П': 'P', 'Ъ': '*', 'Ё': 'Jo', 'Р': 'R', 'Ы': 'Y', 'Ж': 'Zh',
'С': 'S', 'Ь': "'", 'З': 'Z', 'Т': 'T', 'Э': 'Je', 'И': 'I', 'У': 'U', 'Ю': 'Ju', 'Й': 'J', 'Ф': 'F', 'Я': 'Ya'}
filename = input()
with open(filename, 'r', encoding='utf-8') as source, open('result.txt', 'w', encoding='utf-8') as tr_result:
for l in source.read():
trans = translit.get(l.lower(), l)
tr_result.write(trans if l.islower() else trans.capitalize())
Задание 10
Имеется лог-файл crm_log.txt с
информацией о времени входа пользователей в CRM-систему и о времени выхода. Напишите программу, которая
определяет пользователей, работавших в системе более 4 часов, и записывает их
имена и фамилии в файл best_employees.txt.
Пример лога crm_log.txt:
Егор Тимофеев, 09:10, 16:50
Марина Абрамова, 12:00, 15:59
Никита Круглов, 09:10, 12:45
Анна Семенова, 08:10, 12:30
Юлия Сафонова, 10:10, 10:50
Михаил Колесников, 11:10, 12:10
Ожидаемый результат в файле best_employees.txt:
Егор Тимофеев
Анна Семенова
Решение:
with open('crm_log.txt', encoding='utf-8') as file_input, \
open('best_employees.txt', 'w', encoding='utf-8') as file_output:
for line in file_input:
start, end = [int(h) * 60 + int(m) for t in line.split(', ')[1:] for h, m in [t.split(':')]]
if end - start > 240:
file_output.write(line.split(', ')[0] + '\n')
Подведем итоги
Python
предоставляет множество простых и удобных методов для работы с файловой
системой и файлами. С помощью этих методов можно легко:
- Получать любую информацию о файлах и директориях.
- Создавать, изменять, перемещать и удалять директории и файлы.
- Проводить любые операции с содержимым текстовых и двоичных файлов.
В следующей статье будем изучать регулярные выражения.
***
Содержание самоучителя
- Особенности, сферы применения, установка, онлайн IDE
- Все, что нужно для изучения Python с нуля – книги, сайты, каналы и курсы
- Типы данных: преобразование и базовые операции
- Методы работы со строками
- Методы работы со списками и списковыми включениями
- Методы работы со словарями и генераторами словарей
- Методы работы с кортежами
- Методы работы со множествами
- Особенности цикла for
- Условный цикл while
- Функции с позиционными и именованными аргументами
- Анонимные функции
- Рекурсивные функции
- Функции высшего порядка, замыкания и декораторы
- Методы работы с файлами и файловой системой
- Регулярные выражения
- Основы скрапинга и парсинга
- Основы ООП: инкапсуляция и наследование
- Основы ООП – абстракция и полиморфизм
- Графический интерфейс на Tkinter
- Основы разработки игр на Pygame
- Основы работы с SQLite
- Основы веб-разработки на Flask
- Основы работы с NumPy
- Основы анализа данных с Pandas
Программа на Python — это не только функционал, но и оптимальная система работы с файлами. Например, если вы пишете чат-бот, вам нужно загрузить в него готовые ответы в файле txt. Если вы сделали программу для обработки фото — здесь ваш код на Python должен быть готов обрабатывать файлы, которые загрузит в сервис пользователь.
В этой статье разберемся, как работать с файлами на Python, какие для этого есть библиотеки и методы.
Что такое файл
На любом компьютере и в любой операционной системе есть файлы — область данных со своим именем, хранящаяся на носителе. Их принято считать базовыми объектами, из которых складываются директории. В Python с помощью файлов можно сохранять результат работы программы или получать из них данные для обработки в коде.
С любыми файлами можно производить действия, которые делятся на три группы:
- открытие;
- операции чтения из файла и записи в файл;
- закрытие.
Разберемся со всеми действиями по порядку.
Открытие файла на чтение и запись в Python
На компьютере файл надо открыть перед тем, как вносить в него изменения. Такое же правила действует и для Python: нужно открыть файл на чтение и запись. Без этапа открытия нельзя читать содержимое или изменять его. Открыть файл можно с помощью функции open()
:
open(file, mode='rt')
В функцию в качестве аргументов требуется передать путь файлу (file) и выбрать режим работы (mode). По умолчанию Python выбирает значение rt
, но доступны и другие режимы:
Можно комбинировать режимы и использовать сразу несколько. К примеру, по умолчанию функция open()
принимает аргумент rt
. Это значит, что файл будет открыт в виде текстового документа для чтения. С помощью r+
и w+
можно открыть файл сразу для чтения и записи на Python. В первом случае несуществующие файлы будут создаваться, а во втором такое действие спровоцирует вызов исключения.
Если в Python надо открыть файл data.txt в виде текстового документа с правами для чтения, то для этого следует использовать следующий код:
f = open('data.txt')
При этом Python установит режим открытия файла по умолчанию. Если нужен другой режим, то следует передать в функцию аргументы mode:
f = open('data.txt', 'w+')
После окончания работы файлы надо закрывать — так же, как мы это делаем на компьютере. Для этого используется функция close()
после кода взаимодействия с файлом:
f = open('data.txt', 'w+') # действия с файлом f.close()
Также файлы можно открывать с помощью менеджера контекста with
. В этом случае файл автоматически закроется, когда работа с ним завершится:
with open('data.txt', 'w+') as f: # действия с файлом
При открытии файла можно дополнительно указать кодировку, если нужна специфическая или требуется больше контроля над работой кода:
with open('data.txt', 'w+', encoding='utf-8') as f: # действия с файлом
Кодировку можно указать третьим параметром и при обычном способе открытия:
f = open('data.txt', 'w+', encoding='utf-8') # действия с файлом f.close()
Чтение файла
Чтение из файла Python можно реализовать с помощью функции read(), если он открыт в режиме чтения r
. Синтаксис функции выглядит следующим образом:
file.read(size)
В строке выше file
обозначает объект, с которым работаем, а size
— количество символов для чтения. Если ничего не указать в качестве аргумента функции read()
, то получится прочитать сразу все содержимое документа.
Для примера: создадим в проекте file.txt и запишем в него строку «Привет, Python!». Теперь прочитаем первые шесть символов из файла:
with open('file.txt', 'r', encoding='utf-8') as f: data = f.read(6) print(data)
Если запустить код, то Python выведет в консоль фразу «Привет» — это и есть первые шесть символов строки «Привет, Python!» в file.txt:
>>> Привет
Теперь отредактируем код. В этом примере не будем передавать никакие аргументы в функцию read()
:
with open('file.txt', 'r', encoding='utf-8') as f: data = f.read() print(data) >>> Привет, Python!
В этом случае система выводит сразу все содержимое файла.
Содержимое файла можно считывать построчно. Убедимся в этом, отредактировав file.txt. Добавим в него список продуктов:
Морковь Сметана Мука Яблоки
Теперь прочитаем этот список с помощью функции readline()
:
with open('file.txt', 'r', encoding='utf-8') as f: print(f.readline()) >>> Морковь
Python прочитал первую строку списка продуктов. Если вызвать функцию readline()
несколько раз, то получится прочитать последующие строки файла:
with open('file.txt', 'r', encoding='utf-8') as f: print(f.readline()) print(f.readline()) print(f.readline()) print(f.readline()) >>> Морковь >>> Сметана >>> Мука >>> Яблоки
Более удобно последовательное чтение с помощью readline()
можно реализовать в цикле:
with open('file.txt', 'r', encoding='utf-8') as f: for line in f: print(line) >>> Морковь >>> Сметана >>> Мука >>> Яблоки
Все строки файла можно прочитать с помощью метода readlines()
, возвращающего содержимое в виде списка вместе со специальными символами:
with open('file.txt', 'r', encoding='utf-8') as f: data = f.readlines() print(data) >>> ['Морковь\n', 'Сметана\n', 'Мука\n', 'Яблоки']
Такое чтение можно реализовать и без метода readlines()
, воспользовавшись конструктором списков list()
:
with open('file.txt', 'r', encoding='utf-8') as f: data = list(f) print(data) >>> ['Морковь\n', 'Сметана\n', 'Мука\n', 'Яблоки']
При чтении всего файла в Python стоит помнить, что он может быть слишком большим. Если разместить его полностью в оперативной памяти компьютера не получается, следует считывать его частями.
Запись в файл на Python
Для записи файла в Python используется функция write()
. В качестве аргумента ей следует передать строку, содержимое которой будет записано:
file.write(string)
Удалим все содержимое file.txt и запишем в него строку «Привет, Python!»:
with open('file.txt', 'a', encoding='utf-8') as f: data = 'Привет, Python!' f.write(data)
Обратите внимание, что в этом примере мы открыли файл в режиме a, что позволяет записывать новые строки в конец. Выполняем код, открываем файл — теперь в нем содержится строка «Привет, Python!».
В файл можно записать сразу список строк. Для этого применяется метод writelines()
, которому в качестве аргумента надо передать сам список. В качестве примера создадим переменную со списком продуктов и запишем ее в file.txt:
with open('file.txt', 'a', encoding='utf-8') as f: grocery = ['Морковь', 'Яблоки', 'Мука', 'Молоко'] f.writelines(grocery)
Если выполнить код и проверить file.txt, то мы увидим единую строку без пробелов. Все дело в том, что метод writelines()
не добавляет разделители строк автоматически. Нужно сделать это вручную, прописав \n
каждому элементу списка:
with open('file.txt', 'a', encoding='utf-8') as f: grocery = ['Морковь\n', 'Яблоки\n', 'Мука\n', 'Молоко\n'] f.writelines(grocery)
Теперь при выполнении кода каждый элемент списка будет записываться на новую строку.
Управление указателем
В Python есть возможность явно задать позицию указателя в файле — для этого используется метод seek(). Узнать текущую позицию можно с помощью метода tell()
.
Рассмотрим принципы работы с методами на примере. Откроем file.txt в режиме доступа r+ и запишем в него строку «0123456789ABCDEF»:
with open('file.txt', 'r+', encoding='utf-8') as f: f.write('0123456789ABCDEF')
Теперь прочитаем седьмой символ в строке. Для этого воспользуемся методом seek()
для перемещения указателя. В качестве аргумента надо передать функции аргумент смещения в байтах. Вспомним, что нумерация строк начинается с нуля, а нам надо прочитать седьмой символ строки. Значит, укажем смещение в шесть байтов:
with open('file.txt', 'r+', encoding='utf-8') as f: f.write('123456789ABCDEF') f.seek(5) data = f.read(1) print(data) >>> 6
Можно осуществить смещение с конца, тогда в качестве второго элемента надо передать отправную точку для формирования смещения. Всего доступны три начальные позиции:
- 0 — от начала файла;
- 1 — от текущей позиции;
- 2 — от конца файла.
Теперь прочитаем четвертый символ с конца строки:
with open('file.txt', 'r+b') as f: f.seek(-4, 2) data = f.read(1) print(data) >>> b'C'
Узнать байт позиции указателя можно с помощью метода tell()
:
with open('file.txt', 'r+', encoding='utf-8') as f: f.write('123456789ABCDEF') f.read(5) print(f.tell())
Работа с файловой системой
В Python можно работать не только с конкретным файлом, но и со всей системой. Перемещаться между каталогами, создавать новые файлы и переименовывать существующие.
Для работы с файловой системой на Python используют встроенная библиотека OS. Ее необходимо отдельно импортировать в код проекта, чтобы получить доступа к ее методам:
import os
Теперь узнаем с помощью Python текущий каталог. Делаем это с помощью метода getcwd()
. В выводе метода получим путь к папке, в которой сейчас находимся:
import os print(os.getcwd()) >>> /Users/daniilshat/PycharmProjects/pythonProject
С помощью метода listdir()
можно получить список с содержимым каталога. В качестве аргумента можно передать путь к директории; если этого не сделать, то система покажет содержимое текущего каталога:
import os # содержимое текущего каталога print(os.listdir()) # содержимое директории PycharmProjects print(os.listdir('/Users/daniilshat/PycharmProjects')) >>> ['file.txt', 'main.py', '.idea'] >>> ['.DS_Store', 'pythonProject', 'bot', 'love-couples']
Для создания новых директорий файлов в Python используют метод mkdir()
. В качестве аргумента ему надо передать полный путь, включая название новой директории. Для примера создадим директорию Example в PycharmProjects:
import os # содержимое директории PycharmProjects до создания print(os.listdir('/Users/daniilshat/PycharmProjects')) os.mkdir('/Users/daniilshat/PycharmProjects/Example') # содержимое директории PycharmProjects после создания print(os.listdir('/Users/daniilshat/PycharmProjects')) >>> ['.DS_Store', 'pythonProject', 'bot', 'love-couples'] >>> ['.DS_Store', 'pythonProject', 'Example', 'bot', 'love-couples']
С помощью Python можно переименовывать файлы и директории. Для этого используется метода rename()
, которому необходимо передать в качестве аргументов путь к старому и новым файлам. Переименуем директорию Example в New Example:
import os dir = '/Users/daniilshat/PycharmProjects' old_file = os.path.join(dir, 'Example') new_file = os.path.join(dir, 'New Example') # содержимое директории PycharmProjects до переименования print(os.listdir(dir)) os.rename(old_file, new_file) # содержимое директории PycharmProjects после переименования создания print(os.listdir(dir)) >>> ['.DS_Store', 'pythonProject', 'Example', 'bot', 'love-couples'] >>> ['.DS_Store', 'pythonProject', 'bot', 'New Example', 'love-couples']
Для удаления пустых директорий файлов в Python можно использовать метод rmdir()
, а для удаления директории со всем содержимым — shutil.rmtree()
. В качестве аргумента требуется передать путь к директории. Для примера удалим директорию New Example, которую недавно создали:
import os # содержимое директории PycharmProjects до удаления print(os.listdir('/Users/daniilshat/PycharmProjects')) os.rmdir('/Users/daniilshat/PycharmProjects/New Example') # содержимое директории PycharmProjects после удаления print(os.listdir('/Users/daniilshat/PycharmProjects')) >>> ['.DS_Store', 'pythonProject', 'bot', 'New Example', 'love-couples'] >>> ['.DS_Store', 'pythonProject', 'bot', 'love-couples']
Коротко о том, как работать с файлами в Python
В Python можно работать с файлами и получать доступ к файловой системе для изменения каталогов и директорий. Все это можно делать с помощью кода. В Python для этого предусмотрены следующие методы.
Метод | Что делает |
os.getcwd() | Узнать текущий каталог |
os.listdir(path) | Узнать список содержимого каталога |
os.mkdir(path) | Создать директорию |
os.rename(old_file, new_file) | Переименовать файл или директорию |
os.rmdir(path) | Удалить пустую директорию |
shutil.rmtree(path) | Удалить директорию со всем содержимым |
file.read(size) | Прочитать определенное количество символов из файла |
file.readline() | Прочитать строку из файла |
file.readlines() | Прочитать все строки из файла |
file.write(string) | Записать строку в файл |
file.writelines(list) | Записать список строк в файл |
file.seek(int) | Переместить указатель |
file.tell() | Узнать текущее положение указателя |
Взаимодействие с файловой системой#
Нередко требуется программными средствами взаимодействовать с файловой системой и в стандартной библиотеке python
реализовано много инструментов, значительно упрощающих этот процесс.
Путь к файлу/директории#
Путь (англ. path) — набор символов, показывающий расположение файла или каталога в файловой системе (источник — wikipedia). В программных средах путь необходим, например, для того, чтобы открывать и сохранять файлы. В большинстве случаев в python
путь представляется в виде обычного строкового объекта.
Обычно путь представляет собой последовательность вложенных каталогов, разделенных специальным символом, при этом разделитель каталогов может меняться в зависимости от операционной системы: в OS Windows
используется “\
”, в unix-like
системах — “/
”. Кроме того, важно знать, что пути бывают абсолютными и относительными. Абсолютный путь всегда начинается с корневого каталога файловой системы (в OS Windows
— это логический раздел (например, “C:”), в UNIX-like
системах — “/”) и всегда указывает на один и тот же файл (или директорию). Относительный путь, наоборот, не начинается с корневого каталога и указывает расположение относительно текущего рабочего каталога, а значит будет указывать на совершено другой файл, если поменять рабочий каталог.
Итого, например, путь к файлу “hello.py” в домашней директории пользователя “ivan” в зависимости от операционной системы будет выглядеть приблизительно следующим образом:
|
|
|
---|---|---|
Глобальный |
C:\Users\ivan\hello.py |
/home/users/ivan/hello.py |
Относительный |
.\hello.py |
./hello.py |
В связи с этим требуется прикладывать дополнительные усилия, чтобы заставить работать один и тот же код на машинах с разными операционными системами. Чтобы все же абстрагироваться от того, как конкретно устроена файловая система на каждой конкретной машине, в python
предусмотренны модули стандартной библиотеки os.path и pathlib.
Проблема с путями в стиле Windows
#
Как было отмечено выше, в Windows
в качестве разделителя используется символ обратного слеша (backslash) “\
”. Это может привести к небольшой путанице у неопытных программистов. Дело в том, что во многих языка программирования (и в python
, в том числе) символ “\
” внутри строк зарезервирован для экранирования, т.е. если внутри строки встречается “
“, то он интерпретируется не буквально как символ обратного слеша, а изменяет смысл следующего за ним символом. Так, например, последовательность "\n"
представляет собой один управляющий символ перевода строки.
new_line = "\n" print(len(new_line))
Это значит, что если вы попробуете записать Windows
путь не учитывая эту особенность, то высока вероятность получить не тот результат, который вы ожидали. Например, строка "C:\Users"
вообще не корректна с точки зрения синтаксиса python
:
users_folder = "C:\Users"
Input In [10] users_folder = "C:\Users" ^ SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \UXXXXXXXX escape
Это объясняется тем, что последовательность "\U"
используется для экранирования unicode
последовательностей, а набор символов "sers"
не является корректным unicode
кодом. Ниже приводится пример корректного unicode
кода.
snake_emoji = "\U0001F40D" print(snake_emoji)
В python
предусмотренно как минимум два подхода борьбы с этой проблемой.
Первый из них опирается на удвоение количества символов “\
”. Дело в том, что в последовательности символов “\\
” — первый обратный слеш экранирует второй, т.е. итоговый результат эквивалентен одному настоящему символу обратного слеша.
users_folder = "C:\\Users" print(users_folder) new_line = "\\n" print(len(new_line))
Второй способ опирается на использование так называемых сырых (raw) строк: если перед началом литерала строки поставить символ “r
”, то символ обратного слеша теряет свою особую роль внутри неё.
users_folder = r"C:\Users" print(users_folder) new_line = r"\n" print(len(new_line))
Сам факт того, что при ручном прописывании пути в виде строки приходится проявлять дополнительную бдительность намекает на то, что должен быть более осмысленный способ составлении пути.
/
Соединение элементов пути#
Рассмотрим конкретный пример. Пусть у нас имеется строка folder
, представляющая путь к каталогу, и строка filename
, представляющее имя некоего файла внутри этого каталога.
folder = "directory" filename = "file.txt"
Чтобы открыть этот файл, нам потребуется соединить эти две строки, учитывая разделитель каталогов.
Конечно, можно вспомнить, что путь — строка, а значит их можно конкатенировать. Но, что если кто-то захочет запустить ваш код на машине с другой операционной системой? Гораздо целесообразнее воспользоваться для этих целей специальными средствами. Самый надежный способ — метод os.path.join, который на вход принимает произвольное количество имен файлов и соединяет их тем символом, который используется в качестве разделителя на той конкретной машине, на которой скрипт запущен сейчас.
import os path = os.path.join(folder, filename) print(path)
Альтернативой является модуль pathlib, который позволяет обращаться с путями файловой системы в объектно ориентированном стиле, т.е. путь больше не представляется в виде строки, а в виде специального объекта, который в любой момент может быть приведен к строке конструктором строки str.
Для создания такого объекта обычно используют класс Path, при создании экземпляра которого учитывается операционная система, на которой запущен данный скрипт.
from pathlib import Path folder = Path(folder) print(f"{folder=}, {str(folder)=}")
folder=WindowsPath('directory'), str(folder)='directory'
В ячейке выше создается объект типа Path
из строки folder
и вывод сообщает, что создался объект WindowsPath('directory
. Обратите внимание, что автоматически создался путь OS Windows
, т.к. этот скрипт запускался под управлением этой операционной системы.
Чтобы присоединить имя файла к объекту folder
, можно использовать оператор “/
” вне зависимости от операционной системы.
path = folder / filename print(f"{path=}, {str(path)=}")
path=WindowsPath('directory/file.txt'), str(path)='directory\\file.txt'
Обратите внимание на то, что при приведении к строке автоматически получилась строка с разделителем в стиле OS Windows
, т.к. при генерации материалов использовался компьютер под управлением OS Windows
.
Автор курса рекомендует всегда использовать средства модулей os.path или pathlib, даже если вам известно, что ваш скрипт будет запускаться под управлением какой-то конкретной операционной системы, чтобы писать более надежный код и формировать полезные привычки.
Извлечение элементов из пути#
Иногда может стоять обратная задача: дан путь, а из него надо что-то извлечь.
path = r"C:\Users\fadeev\folder\file.txt"
Метод os.path.splitdrive разбивает строку на логический раздел и остальное (актуально в основном на OS Windows
).
print(f"{path=}") drive, tail = os.path.splitdrive(path) print(f"{drive=}, {tail=}")
path='C:\\Users\\fadeev\\folder\\file.txt' drive='C:', tail='\\Users\\fadeev\\folder\\file.txt'
Метод os.path.dirname выделяет из пути родительский каталог.
parent_folder = os.path.dirname(path) print(f"{parent_folder=}")
parent_folder='C:\\Users\\fadeev\\folder'
Метод os.path.basename наоборот извлекает имя файла или папки, на которую данный путь указывает без учета родительского каталога.
filename = os.path.basename(path) print(f"{filename=}")
Метаинформация файла/каталога#
Имея путь, можно запрашивать у операционной системы информацию о том, что находится по этому пути. Важно понимать, что на этом этапе всегда происходит запрос к операционной системе и, если у запустившего программу пользователя не хватает привилегий для выполнения запрошенной операции, то в зависимости от операционной системы вы можете получить разные ответы.
Самый фундаментальный вопрос, который можно задать — существует ли вообще что-нибудь по указанному пути? Метод os.path.exists отвечает как раз на этот вопрос.
print(f"{os.path.exists(path)=}, {os.path.exists('filesystem.ipynb')=}")
os.path.exists(path)=False, os.path.exists('filesystem.ipynb')=True
Методы os.path.isdir и os.path.isfile позволяют определить располагает ли по этому пути каталог или файл соответственно. Оба метода возвращают False
, если по переданному пути ничего не располагается.
print(f"{os.path.isdir(folder)=}, {os.path.isfile('filesystem.ipynb')=}")
os.path.isdir(folder)=True, os.path.isfile('filesystem.ipynb')=True
Также иногда бывает полезно узнать время создания (последнего изменения) или последнего доступа к файлу или каталогу. Для этих целей существуют методы os.path.getatime, os.path.getmtime и os.path.getctime. Размер файла можно узнать методом os.path.getsize.
Содержимое каталога#
В ряде задач может потребоваться узнать содержимое определенного каталога, например, чтобы потом в цикле обработать каждый элемент каталога. В самых простых случаях достаточно метода os.listdir, который возвращает список файлов/каталогов в указанной директории. По умолчанию — текущая директория.
for filename in os.listdir(): print(filename, end=" ")
.ipynb_checkpoints about_12_and_so_on.ipynb about_python.ipynb argparse.ipynb custom_classes.ipynb custom_exceptions.ipynb decorators.ipynb dictionaries.ipynb dynamic_typing.ipynb exceptions.ipynb exercises1.ipynb exercises2.ipynb exercises3.ipynb files.ipynb filesystem.ipynb functions.ipynb garbage_collector.ipynb generators.ipynb if_for_range.ipynb inheritance.ipynb iterators.ipynb json.ipynb jupyter.ipynb LBYL_vs_EAFP.ipynb list_comprehensions.ipynb mutability.ipynb numbers_and_lists.ipynb operators_overloading.ipynb polymorphism.ipynb python_scripts.ipynb scripts_vs_modules.ipynb sequencies.ipynb tmp
Важно помнить, что согласно документации этот метод возвращает список файлов в произвольном порядке, т.е. он ни коим образом не отсортирован. Если требуется отсортировать их по названию, например, в алфавитном порядке, то можно воспользоваться встроенной функцией sorted. Практически во всех остальных случаях лучше выбрать os.scandir, которая не только возвращает содержимое каталога (тоже в произвольном порядке), но и метаинформацию о каждом файле.
Метод glob.glob модуля стандартной библиотеки glob позволяет фильтровать содержимое каталога на основе шаблона. В ячейке ниже демонстрируется, как можно найти все файлы в каталоге, которые начинаются с символа “a
”, а завершаются расширением “.ipynb
”.
import glob for filename in glob.glob("a*.ipynb"): print(filename)
about_12_and_so_on.ipynb about_python.ipynb argparse.ipynb
Создание, копирование, перемещение и удаление файлов и каталогов#
Метод os.mkdir создаёт каталог, но две особенности:
-
если такой каталог уже существует, то бросается исключение;
-
если родительского каталога не существует, то тоже бросается исключение.
Альтернативой является метод os.makedirs имеет опциональный параметр exist_ok
, который позволяет игнорировать ошибку, возникающую при попытке создать уже существующий каталог. Кроме того, если для создания указанного каталога, потребуется создать несколько директорий по пути, то они тоже будут созданы.
Таким образом метод os.mkdir более осторожный, т.к. он точно даст знать, если вы пытаетесь повторно создать директорию, а также если вы где-то ошиблись в пути, а метод os.makedirs более гибкий, позволяющий сократить объем кода, но если вы ошиблись при составлении желаемого пути (например, опечатались в имени одного каталога), то вы не получите никакого сообщения об ошибке и итоговая директория все равно будет создана.
Модуль стандартной библиотеки shutil содержит набор методов, имитирующих методы командной строки, что позволяет копировать файлы (методы shutil.copy, shutil.copy2 и shutil.copyfile), копировать директории с их содержимым (метод shutil.copytree), удалять директории (метод shutil.rmtree) и перемещать файлы или директории (метод shutil.move).
Удалять файлы можно методом os.remove.
Последнее обновление: 02.02.2024
Ряд возможностей по работе с каталогами и файлами предоставляет встроенный модуль os. Хотя он содержит много функций,
рассмотрим только основные из них:
-
mkdir(): создает новую папку
-
rmdir(): удаляет папку
-
rename(): переименовывает файл
-
remove(): удаляет файл
Создание и удаление папки
Для создания папки применяется функция mkdir(), в которую передается путь к создаваемой папке:
import os # путь относительно текущего скрипта os.mkdir("hello") # абсолютный путь os.mkdir("c://somedir") os.mkdir("c://somedir/hello")
Для удаления папки используется функция rmdir(), в которую передается путь к удаляемой папке:
import os # путь относительно текущего скрипта os.rmdir("hello") # абсолютный путь os.rmdir("c://somedir/hello")
Переименование файла
Для переименования вызывается функция rename(source, target), первый параметр которой — путь к исходному файлу, а второй — новое имя файла.
В качестве путей могут использоваться как абсолютные, так и относительные. Например, пусть в папке C://SomeDir/ располагается файл
somefile.txt. Переименуем его в файл «hello.txt»:
import os os.rename("C://SomeDir/somefile.txt", "C://SomeDir/hello.txt")
Удаление файла
Для удаления вызывается функция remove(), в которую передается путь к файлу:
import os os.remove("C://SomeDir/hello.txt")
Существование файла
Если мы попытаемся открыть файл, который не существует, то Python выбросит исключение FileNotFoundError. Для отлова исключения мы можем использовать
конструкцию try…except. Однако можно уже до открытия файла проверить, существует ли он или нет с помощью метода os.path.exists(path).
В этот метод передается путь, который необходимо проверить:
filename = input("Введите путь к файлу: ") if os.path.exists(filename): print("Указанный файл существует") else: print("Файл не существует")