Путь, имя и расширение файла
Достаточно часто возникают ситуации, когда у нас есть полное имя файла, а требуется узнать его расширение. Или добавить нужное расширение, когда не известно, ввел его пользователь или нет. Иногда у нас есть относительный путь до файла, а требуется узнать абсолютный. Про основные методы работы с именем файла и будет эта статья.
Абсолютный путь к файлу
Для того чтобы узнать в Python абсолютный путь к файлу, потребуется воспользоваться библиотекой os. Её подключаем с помощью команды import os. В классе path есть метод abspath. Вот пример использования.
import os p = os.path.abspath('file.txt ') print(p) C:\python3\file.txt
Так же можно воспользоваться и стандартной библиотекой pathlib. Она вошла в состав основных библиотек, начиная с версии Python 3.4. До этого надо было ее инсталлировать с помощью команды pip install pathlib. Она предназначена для работы с путями файловой системы в разных ОС и отлично подойдет для решения данной задачи.
import pathlib p = pathlib.Path('file.txt ') print(p) C:\python3\file.txt
Имя файла
Чтобы узнать имя файла из полной строки с путем, воспользуемся методом basename модуля os.
import os name = os.path.basename(r'C:\python3\file.txt ') print(name) file.txt
Здесь перед строкой вставил r, чтобы подавить возможное возникновение служебных символов. Например, в данном случае если не указать r, то \f считалось бы символом перевода страницы.
Без расширения
Теперь разберемся, как в Python узнать имя файла без расширения. Воспользуемся методом splittext. В этот раз для примера возьмем файл с двойным расширением, чтобы проверить, как будут в этой ситуации работать стандартны функции.
from os import path full_name = path.basename(r'C:\python3\file.tar.gz ') name = path.splitext(full_name)[0] print(name) file.tar
Видно, что последнее расширение архиватора gz было отброшено, в то время как расширение несжатого архива tar осталось в имени.
Если же нам нужно только имя, то можно отбросить все символы полученной строки, которые идут после первой точки. Символ точки тоже отбросим.
Дополним предыдущий пример следующим кодом:
index = name.index('.') print(name[:index]) file
Расширение файла
В Python получить расширение файла можно аналогичным образом с помощью той же функции splitext. Она возвращает кортеж. Первый элемент кортежа имя, а второй – расширение. В данном случае нам нужен второй элемент. Индекс второго элемента равен единице, так как отсчет их идет от нуля.
from os import path full_name = path.basename(r'C:\python3\file.tar.gz ') name = path.splitext(full_name)[1] print(name) .gz
Аналогично можно воспользоваться библиотекой pathlib. Воспользуемся методом suffix.
from pathlib import Path print(Path(r'C:\python3\file.tar.gz ').suffix) .gz
Но в нашем случае два расширения. Их можно узнать с помощью функции suffixes. Она возвращает список, элементами которого и будут расширения. Ниже приведен пример получения списка расширений.
from pathlib import Path print(Path(r'C:\python3\file.tar.gz ').suffixes) ['.tar', '.gz ']
Для того, чтобы получить имя файла или расширение из полного пути или для получения абсолютного пути к файлу используйте библиотеки os и pathlib. Лучше воспользоваться готовым решением из стандартой библиотеками, чем писать свое решение.
Различия в оставления пути к файлу в Unix и Windows
При доступе к файлу в операционной системе требуется правильно указать путь к файлу. Путь к файлу — это строка, которая представляет местоположение файла.
Предупреждение. Сразу оговоримся, чтобы не получить геморрой при составлении путей к файлам с системе Windows используйте встроенный модуль pathlib .
# Unix /path/to/file/text.txt # Windows c:\path\to\file\text.txt
Он разбит на три основные части:
- Путь к файлу /path/to/file/ : расположение директории в файловой системе, где папки разделены прямой косой чертой ‘/’ в Unix подобных системах или обратной косой чертой ‘\’ в Windows.
- Имя файла text : фактическое имя файла.
- Расширение .txt : используется для указания типа файла.
Для чтения или записи в файл нам необходимо его открыть, а для этого нужно передать путь к нужному файлу в качестве строки функции open() . Для Unix подобных систем это делается просто:
>>> full_path = '/path/to/file/text.txt' >>> print(full_path) # /path/to/file/text.txt
В системе Windows путь включает в себя обратную косую черту ‘\’ . Этот символ в строках на Python используется для экранирования [escape-последовательностей][escape-sequence], таких как новая строка ‘\n’ .
>>> full_path = 'c:\path\to\file\text.txt' >>> print(full_path) # c:\path o # ile ext.txt
Что бы избежать Windows системах такого безобразия, нам нужно вручную экранировать обратную косую черту ‘\\’ или передавать в функции open() сырую (необработанную) строку, указав перед первой кавычкой строковой литерал ‘r’ :
# экранируем обратную косую черту >>> full_path = 'c:\\path\\to\\file\\text.txt' >>> print(full_path) # c:\path\to\file\text.txt # строковой литерал raw строки >>> full_path = r'c:\path\to\file\text.txt' >>> print(full_path) # c:\path\to\file\text.txt
А вот как просто создавать и использовать пути при помощи встроенного модуля pathlib . Так как модуль встроенный, то устанавливать ничего не надо.
Строковое представление пути можно посмотреть функцией str() — это сам необработанный путь к файловой системе в собственном виде, например с обратным слешем в Windows, который можно передать любой функции, принимающей путь к файлу в виде строки:
>>> import pathlib # Код запущен на Unix системах >>> path = pathlib.Path('/foo', 'bar', 'baz') >>> path # PosixPath('/foo/bar/baz') >>> str(path) # '/foo/bar/baz' # Код запущен на Windows системе >>> path = pathlib.Path('c:/', 'foo', 'bar') >>> path # WindowsPath('c:/foo/bar') # Строковое представление пути # экранирование происходит автоматически >>> str(path) # 'c:\\foo\\bar'
Переводить путь в текстовое представление не обязательно, т.к. объект пути модуля pathlib принимают все функции.
Оператор косой черты помогает создавать дочерние пути, аналогично os.path.join():
>>> import pathlib # Сложение путей файловой системы >>> p = pathlib.Path('/etc') >>> p # PosixPath('/etc') >>> p1 = p / 'init.d' / 'apache2' >>> p1 # PosixPath('/etc/init.d/apache2') >>> q = pathlib.Path('bin') >>> q1 = '/usr' / q >>> q1 # PosixPath('/usr/bin')
# разложение пути >>> p = pathlib.Path('c:/Program Files/PSF') >>> p.parts # ('c:\\', 'Program Files', 'PSF') >>> p.is_dir() # True # определение диска >>> pathlib.Path('c:/Program Files/').drive # 'c:' >>> pathlib.Path('/Program Files/').drive # '' # определение родительской директории >>> p = pathlib.Path('c:/foo/bar/setup.py') >>> p.is_file() # True >>> p.parents[0] # WindowsPath('c:/foo/bar') >>> p.parents[1] # WindowsPath('c:/foo') >>> p.parents[2] # WindowsPath('c:/') # Двигаемся вверх по директории >>> for up in p.parents: . print(up) . # c:\foo\bar # c:\foo # c:\
- ОБЗОРНАЯ СТРАНИЦА РАЗДЕЛА
- Составление пути к файлу в Unix и Windows
- Открытие/закрытие файла для чтения/записи
- Типы обрабатываемых данных и файлов
- Способы чтения открытого файла
- Способы записи в открытый файл
- Одновременное чтение из одного и запись в другой файл
- Добавление данных в открытый файл
- Управление указателем чтения/записи в файле
- Создание менеджера для обработки файла
- Сохранение словарей в формат JSON
- Встроенные модули для работы с разными форматами
46. Работа с файлами в Python
В этом и последующих уроках мы подробно разберем работу с файлами при помощи встроенных средств Python. Научимся правильно открывать, закрывать файлы, а так же читать и записывать в них.
Открытие файла
Для начала создадим файл с любым именем, например, file.txt в папке с проектом и откроем его при помощи Python в режиме чтения. Для открытия файла в Python существует функция open() :
f = open('file.txt', 'r')
В нашем примере функция open() принимает два аргумента: путь до файла и режим, в котором открывается файл. Можно так же явно указать, что второй аргумент является именно режимом:
f = open('file.txt', mode='r')
Пока не будем вдаваться в подробности использования второго примера, вместо первого. Вернемся к этому вопросу в подразделе «Кодировка».
Аргумент r означает, что файл будет открыт только в режиме чтения. Далее представлены возможные режимы:
- r – открытие файла для чтение (используется по умолчанию);
- w – открытие файла для записи, при этом все содержимое файла удаляется, а в случае отсутствия файла по указанному пути, он создается;
- x – создание нового файла для записи (если файл уже существовал, то возникнет исключение);
- a – открытие файла для записи, при этом содержимое не удаляется, а новая информация добавляется в конец файла;
- b – открытие файла в бинарном режиме;
- t – открытие файла в текстовом режиме (используется по умолчанию);
- + — открытие файла для чтения и записи.
Перечисленные выше режимы открытия файла можно комбинировать. По умолчанию файл открывается в режиме чтения текста, то есть пример открытия файла в режиме чтения можно было написать проще:
f = open('file.txt')
Отлично, мы открыли файл. Теперь необходимо его прочитать и, например, вывести в консоль. Функция open() возвращает объект класса _io.TextIOWrapper :
f = open(‘file.txt’)
print(type(f)) # =>
Объект класса _io.TextIOWrapper имеет атрибуты name , mode и closed , возвращающие имя файла, режим, в котором он открыт и закрыт ли он, соответственно.
f = open('file.txt')
print(f.name) # => file.txt
print(f.mode) # => r
print(f.closed) # => False
f.close() # закрываем файл
print(f.closed) # => True
Пока мы не изучали ООП (но скоро дойдем до этой темы), поэтому определение атрибутов постараюсь объяснить на примере. Предположим, у нас есть автомобиль (это класс). Автомобилей может быть бесконечное множество: грузовые, легковые и так далее, это объекты. Все автомобили имеют атрибуты: марка, масса, цвет и так далее, это атрибуты класса. Так же все автомобили выполняют какие-то функции: ехать вперед, поворачивать и так далее, это методы класса.
Путь до файла в Python
Мы открыли файл, который расположен в той же директории, что и файл с программой. Такое случается далеко не всегда. В этом подразделе разберемся более подробно с путем до файла в Python.
Чтобы получить абсолютный путь до файла, необходимо подключить библиотеку os . В классе path есть метод abspath() , который возвращает абсолютный путь до файла указанного в аргументе:
import os
print(os.path.abspath('file.txt')) # => C:\Users\User\file.txt
Теперь мы можем открыть файл, используя абсолютный путь (только необходимо заменить слеши \ на / ):
f = open('C:/Users/User/file.txt')
Или использовать спецификатор r , который указывает на использование строки в «сыром» виде (нечто похожее мы встречали в уроке 2.4.):
f = open(r'C:\Users\User\file.txt')
С абсолютными путями разобрались, но как открыть файл, если он расположен в папке на уровень выше или ниже. Если на одном уровне с файлом программы расположена папка, например, folder и необходимый файл находится в ней, то, чтобы открыть файл, следует использовать такой относительный путь:
f = open('folder/file.txt')
Если файл находится выше на одну директорию, то необходимо использовать обозначение « ../ »:
f = open('../file.txt')
Если на два директории выше, то:
f = open('../../file.txt')
Чтение из файла
Теперь от атрибутов перейдем к методам, а именно, методу чтения файла read() , возвращающего объект строкового типа:
f = open('file.txt')
data = f.read()
print(data)
Метод read() без параметров возвращает содержимое всего файла. Если в параметре написать целочисленное число, то будет возвращено указанное количество символов:
f = open('file.txt')
data = f.read(2)
print(data)
На самом деле, прочитать информацию построчно можно и без метода read() , а только с использованием цикл for.
f = open('file.txt')
for line in f:
print(line)
Обратите внимание на то, что между строками есть пустая. Откуда она берется? В переменную line сохраняется строка целиком, вместе с символом переноса строки \n . Второй перенос добавляется функция print() . Можем это исправить:
f = open('file.txt')
for line in f:
print(line, end='')
В следующем уроке узнаем об еще более удобном и надежном способе чтения данных из файла.
Итак, вы открыли файл и прочитали необходимые данные. Теперь необходимо его корректно закрыть. Для этого существует метод close() .
f.close()
Может возникнуть вопрос, почему разработчики языка сделали close() методом, а не функцией, как open() . Предположим, что open() являлся бы методом:
'file.txt'.open()
В таком случае потребовалось бы, чтобы строковый тип содержал методы для открытия файла и других дополнений для строкового типа. Функция open() создает новый объект для работы с ним, такая реализация намного проще:
open('file.txt')
Тогда почему close() является методом, а не функцией, например:
close(f) # f – объект, который был создан функцией open()
Такой способ был бы то же неэффективным, так как в функцию пришлось бы передавать целый объект. Так как каждый созданный функцией open() объект имеет свои атрибуты и поля, намного проще и лучше, чтобы экземпляр имел метод close() .
f = open('file.txt') # открыли файл
f.close() # закрыли файл
Запись в файл
Читать из файла научились. Теперь попробуем записать в файл при помощи встроенных средств Python. Инициализируем переменную str строкой « Hello, World », откроем файл и запишем ее в него при помощи метода write() :
str = "Hello, World"
f = open('file.txt')
f.write(str)
Программа не запустилась. Все правильно, мы же открыли файл для чтения (так как не указали параметр mode ). Исправим это и откроем файл в режиме с записью в конец файла:
str = "Hello, World"
f = open('file.txt', 'a')
f.write(str)
Запустите пару раз программу и посмотрите содержимое файла file.txt . Кстати, метод write() возвращает количество записанных символов:
str = "Hello, World"
f = open('file.txt', 'a')
print(f.write(str)) # => 12
Теперь напишите текст на кириллице, запустите программу и посмотрите результат в файле file.txt :
str = "Привет"
f = open('file.txt', 'a')
f.write(str)
Какие-то кракозябры? Разберемся в следующем разделе.
Кодировка файла в Python
Вернемся к функции open() , которая открывает файл. Если заглянуть в модуль встроенных функций builtins.py и найти там функцию open() , можно увидеть какие параметры принимает эта функция (с первыми двумя мы уже разобрались):
def open(file, mode='r', buffering=None, encoding=None, errors=None, newline=None, closefd=True)
Чтобы открыть файл в нужной кодировке есть параметр encoding . Теперь откроем наш файл в кодировке UTF-8:
str = "Привет"
f = open('file.txt', 'a', 'utf-8')
f.write(str)
Снова ошибка. Третьим параметром является buffering , в который мы передали аргумент utf-8 . Чтобы это исправить, следует явно указать параметр, в который мы передаем аргумент:
str = "Привет"
f = open('file.txt', 'a', encoding='utf-8')
f.write(str)
Если мы явно указываем параметр, то их порядок не важен:
str = "Привет"
f = open('file.txt', encoding='utf-8', mode='a')
f.write(str)
После окончания работы с файлом, необходимо его закрыть с помощью метода close() :
…
f.write(str)
f.close()
Об аргументах и параметрах мы еще будем говорить в теме «Функции».
В этом уроке разобрались, как открывать файлы в разных режимах в Python, познакомились с абсолютными и относительными путями, научились читать из файла и записывать в него.
В следующем уроке познакомимся с более современным и надежным способом открытия файла, при помощи конструкции with/as , которая гарантирует закрытие файла в любом случае.
Как указать путь к файлу в python
На этом шаге мы рассмотрим особенности открытия файла, определения текущего каталога .
Очень часто нужно сохранить какие-либо данные. Для этого существуют два способа: запись в файл и сохранение в базу данных . Первый способ используется при сохранении информации небольшого объема. Если объем велик, то лучше (и удобнее) воспользоваться базой данных.
Открытие файла
Прежде чем работать с файлом, необходимо создать объект файла с помощью функции open () . Функция имеет следующий формат:
open(Путь к файлу>[, mode = 'r'] [, buffering=-1] [, encoding=None] [, errors=None][, newline=None][, closefd=True])
В первом параметре указывается путь к файлу. Путь может быть абсолютным или относительным. При указании абсолютного пути в Windows следует учитывать, что в Python слеш является специальным символом. По этой причине слеш необходимо удваивать или вместо обычных строк использовать неформатированные строки. Пример:
>>> "C:\\temp\\new\\file.txt" # Правильно 'C:\\temp\\new\\file.txt' >>> r"C:\temp\new\file.txt" # Правильно 'C:\\temp\\new\\file.txt' >>> "C:\temp\new\file.txt" # Неправильно. 'C:\temp\new\x0cile.txt'
Обратите внимание на последний пример. В этом пути из-за того, что слеши не удвоены, возникло присутствие сразу трех специальных символов: \t , \n и \f (отображается как \x0c ). После преобразования этих специальных символов путь будет выглядеть следующим образом: . , . .
С:Табуляция>empПеревод строки>ewПеревод формата>ile.txt
Если такую строку передать в функцию open () , то это приведет к исключению OSError :
>>> open("C:\temp\new\file.txt") Traceback (most recent call last): File "", line 1, in open("C:\temp\new\file.txt") OSError: [Errno 22] Invalid argument: 'C:\temp\new\x0cile.txt'
если открываемый файл находится в текущем рабочем каталоге, то можно указать только название файла. Пример:
>>> import os.path # Подключаем модуль >>> # Файл в текущем рабочем каталоге (C:\Python34\) >>> os.path.abspath(r"file.txt") 'C:\\Python34\\file.txt'
>>> # Открываемый файл в C:\Python34\folder1\ >>> os.path.abspath (r"folder1/file.txt") 'C:\\Python34\\folder1\\file.txt' >>> # Открываемый файл в C:\Python34\folder1\folder2\ >>> os.path.abspath(r"folder1/folder2/file.txt") 'C:\\Python34\\folder1\\folder2\\file.txt'
>>> # Открываемый файл в С:\ >>> os.path.abspath (r"../file.txt") 'C:\\file.txt'
>>> # Открываемый файл в C:\book\folder1\ >>> os.path.abspath (r"/book/folder1/file.txt") 'C:\\book\\folder1\\file.txt' >>> # Открываемый файл в C:\book\folder1\folder2\ >>> os.path.abspath (r"/book/folder1/folder2/file.txt") 'C:\\book\\folder1\\folder2\\file.txt'
Как можно видеть, в абсолютном и относительном путях можно указать как прямые, так и обратные слеши. Все они будут автоматически преобразованы с учетом значения атрибута sep из модуля os.path . Значение этого атрибута зависит от используемой операционной системы. Выведем значение атрибута sep в операционной системе Windows :
>>> os.path.sep '\\' >>> os.path.abspath (r"С:/book/folder1/file.txt") 'С:\\book\\folder1\\file.txt'
При использовании относительного пути необходимо учитывать местоположение текущего рабочего каталога, т. к. рабочий каталог не всегда совпадает с каталогом, в котором находится исполняемый файл. Если файл запускается с помощью двойного щелчка на его значке, то каталоги будут совпадать. Если же файл запускается из командной строки, то текущим рабочим каталогом будет каталог, из которого запускается файл.
Рассмотрим все это на примере, для чего в каталоге C:\book создадим следующую структуру файлов:
С:\book\ test.py folder1\ __init__.py module1.py
Содержимое файла C:\book\test.py :
# -*- coding: utf-8 -*- import os, sys print("%-25s%s" % ("Файл:", os.path.abspath(__file__))) print("%-25s%s" % ("Текущий рабочий каталог:", os.getcwd())) print("%-25s%s" % ("Каталог для импорта:", sys.path[0])) print("%-25s%s" % ("Путь к файлу:", os.path.abspath("file.txt"))) print("-" * 40) import folder1.module1 as m m.get_cwd()
Файл C:\book\folder1\__init__.py создаем пустым. Как вы уже знаете, этот файл указывает интерпретатору Python , что данный каталог является пакетом с модулями.
Содержимое файла C:\book\folder1\module1.py :
# -*- coding: utf-8 -*- import os, sys def get_cwd(): print("%-25s%s" % ("Файл:", os.path.abspath(__file__))) print("%-25s%s" % ("Текущий рабочий каталог:", os.getcwd())) print("%-25s%s" % ("Каталог для импорта:", sys.path[0])) print("%-25s%s" % ("Путь к файлу:", os.path.abspath("file.txt")))
Архив со структурой каталогов и файлами можно взять здесь.
Запускаем командную строку, переходим в каталог C:\book и запускаем файл test.py :
Рис.1. Результат выполнения файла test.py
В этом примере текущий рабочий каталог совпадает с каталогом, в котором расположен файл test.py . Однако обратите внимание на текущий рабочий каталог внутри модуля module1.py . Если внутри этого модуля в функции open() указать название файла без пути, то поиск файла будет произведен в каталоге C:\book , а не C:\book\folder1 .
Теперь перейдем в корень диска С: и опять запустим файл test.py :
Рис.2. Результат выполнения файла test.py
В этом случае текущий рабочий каталог не совпадает с каталогом, в котором расположен файл test.py . Если внутри файлов test.py и module1.py в функции open() указать название файла без пути, то поиск файла будет производиться в корне диска С: , а не в каталогах с этими файлами.
Чтобы поиск файла всегда производился в каталоге с исполняемым файлом, необходимо этот каталог сделать текущим с помощью функции chdir() из модуля os . Для примера изменим содержимое файла test.py :
# -*- coding: utf-8 -*- import os, sys # Делаем каталог с исполняемым файлом текущим os.chdir (os.path.dirname(os.path.abspath(__file__))) print("%-25s%s" % ("Файл:", __file__)) print("%-25s%s" % ("Текущий рабочий каталог:", os.getcwd())) print("%-25s%s" % ("Каталог для импорта:", sys.path[0])) print("%-25s%s" % ("Путь к файлу:", os.path.abspath("file.txt")))
Архив с этим файлом можно взять здесь.
Обратите внимание на четвертую строку. С помощью атрибута __file__ мы получаем путь к исполняемому файлу вместе с названием файла. Атрибут __file__ не всегда содержит полный путь к файлу. Например, если запуск осуществляется следующим образом:
С:\book>C:\Python34\python test.py,
то атрибут будет содержать только название файла без пути. Чтобы всегда получать полный путь к файлу, следует передать значение атрибута в функцию abspath() из модуля os.path . Далее мы извлекаем путь (без названия файла) с помощью функции dirname() и передаем его функции chdir() . Теперь, если в функции open() указать название файла без пути, то поиск будет производиться в каталоге с этим файлом. Запустим файл test.py с помощью командной строки:
Рис.3. Результат выполнения файла test.py
Функции, предназначенные для работы с каталогами, мы еще рассмотрим подробно в следующих шагах. Сейчас же важно запомнить, что текущим рабочим каталогом будет каталог, из которого запускается файл, а не каталог, в котором расположен исполняемый файл. Кроме того, пути поиска файлов не имеют никакого отношения к путям поиска модулей.
На следующем шаге мы закончим рассмотрение функции open() .