Для решения задач, связанных с редактированием или чтением файла, необходимо сообщить интерпретатору Python имя нужного нам файла, а также адрес, по которому этот файл располагается. Существуют разные способы указания пути к файлу в Python: от самого простого, до самого правильного. Давайте выясним, чем эти варианты отличаются и почему простой вариант не годится на роль лучшего!
Самый простой вариант — не самый верный!
Внимание! У этого способа обнаружен недостаток!
Самый простой вариант задания пути выглядит как последовательность директорий, в которых находится файл, с именем самого файла, разделенные знаками слеша:
Пример относительного пути:
path = "Files/info.txt" # в Линуксе, или: path = "Files\info.txt" # в Windows
Где вместо «Files» и «info.txt» Вы напишите названия ваших директорий и имя вашего файла соответственно.
Пример абсолютного пути:
path = "/home/my_comp/Files/info.txt" # для Линукс, или: path = "C:\Python\pythonw.exe\Files\info.txt" # для Windows
Где вместо «C:\Python\pythonw.exe\Files\info.txt», «home/my_comp/Files/» и «info.txt» Вы напишите названия ваших директорий и имя вашего файла соответственно.
Этот вариант рабочий, однако, один существенный недостаток лишил его внимания разработчиков. Проблема заключается в том, что заданные таким способом пути адаптированы только к одному виду операционной системы: к Линукс, либо к Windows, так как в Windows используются обратные слеши «\», а в Линукс — обычные «/». Из-за этого скрипт, показывавший отличные результаты в Windows, начнет жаловаться на отсутствие файлов по прописанному пути в Linux, и наоборот. А с абсолютным путем вообще все сложно: никакого диска «C:» в Линуксе нет. Скрипт опять будет ругаться! Что же делать? Правильно указать путь к файлу!
Указываем путь к файлу правильно!
Внимание! Годный вариант!
Python — умный змей, поэтому в его арсенале, начиная с 3.4 версии появился модуль pathlib, который позволяет вытворять самые приятные вещи с путями к файлу, стоит только импортировать его класс Path:
import pathlib from pathlib import Path
Кстати, если у вас не установлен модуль pathlib, это легко исправить с помощью команды:
pip install pathlib
Задаем относительный путь с помощью Path!
После того, как класс импортирован, мы получаем власть над слешами! Теперь вопрос о прямых и обратных слешах в разных операционных системах ложится на плечи Path. Используя Path, вы можете корректно задать относительный путь, который будет работать в разных системах.
Например, в случае расположения файлов, как на представленном изображении, относительный путь, определяемый в скрипте «main_script.py», сформируется автоматически из перечисленных в скобках составных частей. Pathlib инициализирует новый объект класса Path, содержимым которого станет сформированный для Вашей системы относительный путь (в Windows части пути будут разделены обратными слешами, в Linux — обычными):
import pathlib from pathlib import Path path = Path("files", "info", "docs.txt") ## выведем значение переменной path: print(str(path))
## выведем значение переменной path: files/info/docs.txt
У нас появился Telegram-канал для изучающих Python! Канал совсем свежий, подпишись одним из первых, ведь вместе «питонить» веселее! 😉 Ссылка на канал: «Кодим на Python!»
Задаем абсолютный путь с помощью Path
- cwd() — возвращает путь к рабочей директории
- home() — возвращает путь к домашней директории
Полученную строку, содержащую путь к рабочей или домашней директории, объединим с недостающими участками пути при инициализации объекта класса Path :
Пример 1: с использованием функции cwd():
import pathlib from pathlib import Path #Получаем строку, содержащую путь к рабочей директории: dir_path = pathlib.Path.cwd() # Объединяем полученную строку с недостающими частями пути path = Path(dir_path, 'files','info', 'docs.txt') # выведем значение переменной path: print(str(path))
# выведем значение переменной path: "/home/my_comp/python/files/info/docs.txt"
В данном случае путь к директории имеет вид: dir_path = «/home/my_comp/python», а полный путь к файлу «docs.txt» будет иметь вид: «/home/my_comp/python/files/info/docs.txt».
Представленный выше код можно оптимизировать и записать в одну строку:
import pathlib from pathlib import Path path = Path(pathlib.Path.cwd(), 'files', 'info', 'docs.txt') # значение переменной path: print(str(path))
# значение переменной path: "/home/my_comp/python/files/info/docs.txt"
Пример2: с использованием функции home():
import pathlib from pathlib import Path #Получаем строку, содержащую путь к домашней директории: dir_path = pathlib.Path.home() # Объединяем полученную строку с недостающими частями пути path = Path(dir_path, 'files','info', 'docs.txt') # Выведем значение переменной path: print(str(path))
# Выведем значение переменной path: "/home/my_comp/files/info/docs.txt"
В данном случае путь к директории имеет вид: dir_path = «/home/my_comp», а полный путь к файлу ‘docs.txt’ будет иметь вид: «/home/my_comp/files/info/docs.txt».
Сократим представленный выше код:
import pathlib from pathlib import Path path = Path(pathlib.Path.home(), 'files', 'info', 'docs.txt') # Значение переменной path: print(str(path))
# Значение переменной path: "/home/my_comp/files/info/docs.txt"
Подведем итог: начиная с версии Python 3.4, для задания пути к файлу рекомендуется использовать модуль pathlib с классом Path. Определить путь к рабочей директории можно с помощью функции cwd(), а путь к домашней директории подскажет функция home().
Взаимодействие с файловой системой#
Нередко требуется программными средствами взаимодействовать с файловой системой и в стандартной библиотеке 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.
Python — удобный язык, который часто используется для написания сценариев, анализа данных и веб-разработки.
В этой статье мы рассмотрим, как читать и записывать файлы с помощью Python.
Файлы и пути к файлам
У файла есть имя для ссылки на файл. У него также есть путь для определения местоположения файла.
Путь состоит из папки, они могут быть вложенными и образуют путь.
Обратная косая черта в Windows и прямая косая черта в macOS и Linux
В Windows путь состоит из обратной косой черты. Во многих других операционных системах, таких как macOS и Linux, путь состоит из косых черт.
Стандартная pathlib
библиотека Python знает разницу и может соответствующим образом отсортировать их. Следовательно, мы должны использовать его для построения путей, чтобы наша программа работала везде.
Например, мы можем импортировать pathlib
следующим образом и создать объект Path
следующим образом:
from pathlib import Path path = Path('foo', 'bar', 'foo.txt')
После выполнения кода path
должен быть Path
объектом, подобным следующему, если мы запускаем указанную выше программу в Linux или macOS:
PosixPath('foo/bar/foo.txt')
Если мы запустим приведенный выше код в Windows, мы получим объект WindowsPath
вместо объекта PosixPath
.
Использование оператора / для объединения путей
Мы можем использовать оператор /
для объединения путей. Например, мы можем переписать путь, который у нас был, в следующий код:
from pathlib import Path path = Path('foo')/'bar'/'foo.txt'
Тогда мы получим тот же результат, что и раньше.
Это также будет работать в Windows, macOS и Linux, поскольку Python соответствующим образом отсортирует путь.
Чего нам не следует использовать, так это метода join
строки, потому что разделитель путей отличается в Windows и других операционных системах.
Например:
path = '/'.join(['foo', 'bar', 'foo.txt'])
не будет работать в Windows, так как путь имеет косую черту.
Текущий рабочий каталог
Мы можем получить текущий рабочий каталог (CWD), который является каталогом, в котором запущена программа.
Мы можем изменить CWD с помощью функции os.chdir
и получить текущий CWD с помощью функции Path.cwd
.
Например, мы можем написать:
from pathlib import Path import os print(Path.cwd()) os.chdir(Path('foo')/'bar') print(Path.cwd())
Тогда получаем:
/home/runner/AgonizingBasicSpecialist /home/runner/AgonizingBasicSpecialist/foo/bar
как выход.
Как мы видим, chdir
изменил текущий рабочий каталог, так что мы можем управлять файлами в каталогах, отличных от тех, в которых работает программа.
Домашний каталог
Домашний каталог — это корневой каталог папки профиля учетной записи пользователя.
Например, мы можем написать следующее:
from pathlib import Path path = Path.home()
Тогда значение path
будет чем-то вроде PosixPath(‘/home/runner’)
.
Абсолютные и относительные пути
Абсолютный путь — это путь, который всегда начинается с корневой папки. Относительный — это путь относительно текущего рабочего каталога программы.
Например, в Windows C:\Windows
— это абсолютный путь. Относительный путь — это что-то вроде .\foo\bar
. Он начинается с точки, а foo
находится внутри текущего рабочего каталога.
Создание новых папок с помощью функции os.makedirs ()
Мы можем создать новую папку с функцией os.makedirs
.
Например, мы можем написать:
from pathlib import Path Path(Path.cwd()/'foo').mkdir()
Затем мы создаем каталог foo
внутри нашего текущего рабочего каталога.
Обработка абсолютных и относительных путей
Мы можем проверить, является ли путь абсолютным путем с помощью метода is_absolute
.
Например, мы можем написать:
from pathlib import Path is_absolute = Path.cwd().is_absolute()
Тогда мы должны увидеть is_absolute
равным True
, поскольку Path.cwd()
возвращает абсолютный путь.
Мы можем вызвать os.path.abspath
, чтобы вернуть строку с абсолютным путем переданного нами аргумента path
.
Например, учитывая, что у нас есть каталог foo
в текущем рабочем каталоге, мы можем написать:
from pathlib import Path import os path = os.path.abspath(Path('./foo'))
чтобы получить абсолютный путь к папке foo
.
У нас должно получиться что-то вроде:
'/home/runner/AgonizingBasicSpecialist/foo'
как значение path
.
os.path.isabs(path)
— это метод, который возвращает True
— это абсолютный путь.
Метод os.path.relpath(path, start)
вернет строку относительного пути от пути start
до path
.
Если start
не указан, то текущий рабочий каталог используется как начальный путь.
Например, если у нас есть папка /foo/bar
в нашем домашнем каталоге, то мы можем получить путь ./foo/bar
относительно домашнего каталога, написав:
from pathlib import Path import os path = os.path.relpath(Path.home(), Path('./foo')/'bar')
Тогда path
имеет значение ‘../../..’
.
Заключение
Мы можем использовать модули path
и os
для построения путей и управления ими.
Кроме того, мы также можем использовать /
с объектами Path
для создания пути, который работает со всеми операционными системами.
Мы также можем указать пути к функции Path
для построения путей.
Python также имеет методы для проверки относительных и абсолютных путей, а модуль os
может создавать относительные пути из двух абсолютных путей.
Примечание от Python In Plain English
Мы всегда заинтересованы в продвижении качественного контента. Если у вас есть статья, которую вы хотите отправить в какую-либо из наших публикаций, отправьте нам электронное письмо по адресу [email protected] с вашим именем пользователя Medium, и мы добавим вас в качестве автора.
In the file that has the script, you want to do something like this:
import os
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')
This will give you the absolute path to the file you’re looking for. Note that if you’re using setuptools, you should probably use its package resources API instead.
UPDATE: I’m responding to a comment here so I can paste a code sample.
Am I correct in thinking that
__file__
is not always available (e.g. when you run the file directly rather than importing it)?
I’m assuming you mean the __main__
script when you mention running the file directly. If so, that doesn’t appear to be the case on my system (python 2.5.1 on OS X 10.5.7):
#foo.py
import os
print os.getcwd()
print __file__
#in the interactive interpreter
>>> import foo
/Users/jason
foo.py
#and finally, at the shell:
~ % python foo.py
/Users/jason
foo.py
However, I do know that there are some quirks with __file__
on C extensions. For example, I can do this on my Mac:
>>> import collections #note that collections is a C extension in Python 2.5
>>> collections.__file__
'/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-
dynload/collections.so'
However, this raises an exception on my Windows machine.
answered May 27, 2009 at 21:47
Jason BakerJason Baker
193k137 gold badges377 silver badges514 bronze badges
11
It’s 2018 now, and Python has already evolved to the __future__
long time ago. So how about using the amazing pathlib
coming with Python 3.4 to accomplish the task instead of struggling with os
, os.path
, glob
, shutil
, etc.
So we have 3 paths here (possibly duplicated):
mod_path
: which is the path of the simple helper scriptsrc_path
: which contains a couple of template files waiting to be copied.cwd
: current directory, the destination of those template files.
and the problem is: we don’t have the full path of src_path
, only know its relative path to the mod_path
.
Now let’s solve this with the amazing pathlib
:
# Hope you don't be imprisoned by legacy Python code :)
from pathlib import Path
# `cwd`: current directory is straightforward
cwd = Path.cwd()
# `mod_path`: According to the accepted answer and combine with future power
# if we are in the `helper_script.py`
mod_path = Path(__file__).parent
# OR if we are `import helper_script`
mod_path = Path(helper_script.__file__).parent
# `src_path`: with the future power, it's just so straightforward
relative_path_1 = 'same/parent/with/helper/script/'
relative_path_2 = '../../or/any/level/up/'
src_path_1 = (mod_path / relative_path_1).resolve()
src_path_2 = (mod_path / relative_path_2).resolve()
In the future, it’s just that simple.
Moreover, we can select and check and copy/move those template files with pathlib
:
if src_path != cwd:
# When we have different types of files in the `src_path`
for template_path in src_path.glob('*.ini'):
fname = template_path.name
target = cwd / fname
if not target.exists():
# This is the COPY action
with target.open(mode='wb') as fd:
fd.write(template_path.read_bytes())
# If we want MOVE action, we could use:
# template_path.replace(target)
answered Jul 3, 2018 at 7:40
YaOzIYaOzI
16.3k9 gold badges76 silver badges72 bronze badges
3
you need os.path.realpath
(sample below adds the parent directory to your path)
import sys,os
sys.path.append(os.path.realpath('..'))
answered Mar 19, 2012 at 10:24
user989762user989762
1,6963 gold badges16 silver badges20 bronze badges
4
As mentioned in the accepted answer
import os
dir = os.path.dirname(__file__)
filename = os.path.join(dir, '/relative/path/to/file/you/want')
I just want to add that
the latter string can’t begin with the backslash , infact no string
should include a backslash
It should be something like
import os
dir = os.path.dirname(__file__)
filename = os.path.join(dir, 'relative','path','to','file','you','want')
The accepted answer can be misleading in some cases , please refer to this link for details
answered Apr 28, 2016 at 6:22
AhmedAhmed
2,1965 gold badges26 silver badges41 bronze badges
4
Consider my code:
import os
def readFile(filename):
filehandle = open(filename)
print filehandle.read()
filehandle.close()
fileDir = os.path.dirname(os.path.realpath('__file__'))
print fileDir
#For accessing the file in the same folder
filename = "same.txt"
readFile(filename)
#For accessing the file in a folder contained in the current folder
filename = os.path.join(fileDir, 'Folder1.1/same.txt')
readFile(filename)
#For accessing the file in the parent folder of the current folder
filename = os.path.join(fileDir, '../same.txt')
readFile(filename)
#For accessing the file inside a sibling folder.
filename = os.path.join(fileDir, '../Folder2/same.txt')
filename = os.path.abspath(os.path.realpath(filename))
print filename
readFile(filename)
answered Oct 6, 2015 at 15:17
2
See sys.path
As initialized upon program startup, the first item of this list, path[0], is the directory containing the script that was used to invoke the Python interpreter.
Use this path as the root folder from which you apply your relative path
>>> import sys
>>> import os.path
>>> sys.path[0]
'C:\\Python25\\Lib\\idlelib'
>>> os.path.relpath(sys.path[0], "path_to_libs") # if you have python 2.6
>>> os.path.join(sys.path[0], "path_to_libs")
'C:\\Python25\\Lib\\idlelib\\path_to_libs'
answered May 27, 2009 at 21:47
Tom LeysTom Leys
18.5k7 gold badges41 silver badges62 bronze badges
3
Instead of using
import os
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')
as in the accepted answer, it would be more robust to use:
import inspect
import os
dirname = os.path.dirname(os.path.abspath(inspect.stack()[0][1]))
filename = os.path.join(dirname, 'relative/path/to/file/you/want')
because using __file__ will return the file from which the module was loaded, if it was loaded from a file, so if the file with the script is called from elsewhere, the directory returned will not be correct.
These answers give more detail: https://stackoverflow.com/a/31867043/5542253 and https://stackoverflow.com/a/50502/5542253
answered Feb 18, 2016 at 21:41
kmtkmt
77312 silver badges30 bronze badges
1
From what suggest others and from pathlib documentation, a simple (but not ideal) solution is the following (suppose the file we need to refer to is Test/data/users.csv
):
# Current file location: Tests/src/long/module/subdir/some_script.py
from pathlib import Path
# back to Tests/
PROJECT_ROOT = Path(__file__).parents[4]
# then down to Test/data/users.csv
CSV_USERS_PATH = PROJECT_ROOT / 'data' / 'users.csv'
with CSV_USERS_PATH.open() as users:
print(users.read())
This works but looks a bit odd because if you move some_script.py
around, the path to the root of our project may change (and we would therefore need to change the parents[4]
part).
I think I found a better solution that, based on the same idea.
We will use a file paths.py
to store where the root of the project is, this file will remain at the same location compared to the root directory.
Tests
├── data
│ └── users.csv
└── src
├── long
│ └── module
│ └── subdir
│ └── some_script.py
├── main.py
└── paths.py
Where paths.py
‘s only responsability is to provide PROJECT_ROOT
:
from pathlib import Path
PROJECT_ROOT = Path(__file__).parents[1]
All scripts can now use paths.PROJECT_ROOT
to express absolute paths from the root of the project. For example in src/long/module/subdir/some_script.py
we could have:
from paths import PROJECT_ROOT
CSV_USERS_PATH = PROJECT_ROOT / 'data' / 'users.csv'
def hello():
with CSV_USERS_PATH.open() as f:
print(f.read())
And everything goes as expected:
~/Tests/src/$ python main.py
/Users/cglacet/Tests/data/users.csv
hello, user
~/Tests/$ python src/main.py
/Users/cglacet/Tests/data/users.csv
hello, user
The main.py
script simply is:
from long.module.subdir import some_script
some_script.hello()
answered Oct 16, 2020 at 9:38
cglacetcglacet
9,1234 gold badges46 silver badges60 bronze badges
summary of the most important commands
>>> import os
>>> os.path.join('/home/user/tmp', 'subfolder')
'/home/user/tmp/subfolder'
>>> os.path.normpath('/home/user/tmp/../test/..')
'/home/user'
>>> os.path.relpath('/home/user/tmp', '/home/user')
'tmp'
>>> os.path.isabs('/home/user/tmp')
True
>>> os.path.isabs('/tmp')
True
>>> os.path.isabs('tmp')
False
>>> os.path.isabs('./../tmp')
False
>>> os.path.realpath('/home/user/tmp/../test/..') # follows symbolic links
'/home/user'
A detailed description is found in the docs.
These are linux paths. Windows should work analogous.
answered Sep 10, 2020 at 15:09
Markus DutschkeMarkus Dutschke
9,4194 gold badges65 silver badges58 bronze badges
Hi first of all you should understand functions os.path.abspath(path) and os.path.relpath(path)
In short os.path.abspath(path) makes a relative path to absolute path. And if the path provided is itself a absolute path then the function returns the same path.
similarly os.path.relpath(path) makes a absolute path to relative path. And if the path provided is itself a relative path then the function returns the same path.
Below example can let you understand the above concept properly:
suppose i have a file input_file_list.txt which contains list of input files to be processed by my python script.
D:\conc\input1.dic
D:\conc\input2.dic
D:\Copyioconc\input_file_list.txt
If you see above folder structure, input_file_list.txt is present in Copyofconc folder and the files to be processed by the python script are present in conc folder
But the content of the file input_file_list.txt is as shown below:
..\conc\input1.dic
..\conc\input2.dic
And my python script is present in D: drive.
And the relative path provided in the input_file_list.txt file are relative to the path of input_file_list.txt file.
So when python script shall executed the current working directory (use os.getcwd() to get the path)
As my relative path is relative to input_file_list.txt, that is «D:\Copyofconc», i have to change the current working directory to «D:\Copyofconc».
So i have to use os.chdir(‘D:\Copyofconc’), so the current working directory shall be «D:\Copyofconc».
Now to get the files input1.dic and input2.dic, i will read the lines «..\conc\input1.dic» then shall use the command
input1_path= os.path.abspath(‘..\conc\input1.dic’) (to change relative path to absolute path. Here as current working directory is «D:\Copyofconc», the file «.\conc\input1.dic» shall be accessed relative to «D:\Copyofconc»)
so input1_path shall be «D:\conc\input1.dic»
answered Dec 7, 2013 at 4:30
This code will return the absolute path to the main script.
import os
def whereAmI():
return os.path.dirname(os.path.realpath(__import__("__main__").__file__))
This will work even in a module.
answered Mar 24, 2016 at 20:03
BookOwlBookOwl
3783 silver badges11 bronze badges
1
An alternative which works for me:
this_dir = os.path.dirname(__file__)
filename = os.path.realpath("{0}/relative/file.path".format(this_dir))
answered Oct 10, 2014 at 9:19
J0hnG4ltJ0hnG4lt
4,3375 gold badges24 silver badges40 bronze badges
Example
Here’s an example, tested in Python ‘3.9.5`:
your current directory: 'c:\project1\code\'
and you want to access the following folder: 'c:\project1\dataset\train\'
.
Then you can access the folder using the following address: '../dataset/train/'
References
If you want some more information about path in Python
, read this:
PEP - 355
PEP - 519
answered Oct 28, 2021 at 16:38
What worked for me is using sys.path.insert
. Then I specified the directory I needed to go. For example I just needed to go up one directory.
import sys
sys.path.insert(0, '../')
answered Mar 16, 2017 at 18:14
WhitecatWhitecat
3,8827 gold badges48 silver badges78 bronze badges
1
I think to work with all systems use «ntpath» instead of «os.path». Today, it works well with Windows, Linux and Mac OSX.
import ntpath
import os
dirname = ntpath.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')
answered Oct 15, 2020 at 0:08
A simple solution would be
import os
os.chdir(os.path.dirname(__file__))
answered Feb 4, 2021 at 22:21
Qin HeyangQin Heyang
1,4961 gold badge16 silver badges18 bronze badges
From C:\Users\xyz\myFolder
to C:\Users\xyz\testdata
:
import os
working_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
# C:\Users\xyz\myFolder
print(working_dir)
updated_working_dir = os.path.join(os.path.realpath(working_dir + '/../'), 'testdata')
# C:\Users\xyz\testdata
print(updated_working_dir)
Output
C:\Users\xyz\myFolder
C:\Users\xyz\testdata
answered Apr 9, 2021 at 6:56
Here is my sumup:
First, define the tool function named relpath
, which convert a relative path to current file into a relative path to cwd
import os
relpath = lambda p: os.path.normpath(os.path.join(os.path.dirname(__file__), p))
Then we use it to wrap paths which is relative to current file
path1 = relpath('../src/main.py')
And you can also call sys.path.append()
to import file relative to current file position
sys.path.append(relpath('..')) # so that you can import from upper dir
The full example code : https://gist.github.com/luochen1990/9b1ffa30f5c4a721dab5991e040e3eb1
answered Nov 11, 2021 at 1:57
luochen1990luochen1990
3,6791 gold badge22 silver badges38 bronze badges
Say the current archive named «Helper» and the upper directory named «Workshop», and the template files are in \Workshop\Templates, then the relative path in Python is «..\Templates».
answered Nov 17, 2021 at 6:17
This a simple way to add a relative path to the system path set . For example, for frequent case when the target directory is one level above (thus, '/../'
) the working directory:
import os
import sys
workingDir = os.getcwd()
targetDir = os.path.join(os.path.relpath(workingDir + '/../'),'target_directory')
sys.path.insert(0,targetDir)
This solution was tested for:
Python 3.9.6 | packaged by conda-forge | (default, Jul 11 2021,
03:37:25) [MSC v.1916 64 bit (AMD64)]
answered Jan 26, 2022 at 22:46
DanGitRDanGitR
471 silver badge8 bronze badges
I’m not sure if this applies to some of the older versions, but I believe Python 3.3 has native relative path support.
For example the following code should create a text file in the same folder as the python script:
open("text_file_name.txt", "w+t")
(note that there shouldn’t be a forward or backslash at the beginning if it’s a relative path)
answered Jun 4, 2014 at 14:41
1
Файлы используются программами для долговременного хранения информации, как необходимой для собственной работы (например, настройки), так и полученной во время ее исполнения (результаты вычислений и т.д.). Подавляющее большинство программ сегодня в том или ином виде используют файлы, сохраняя результаты работы между сеансами запуска.
Содержание
-
Файлы и файловая система
-
Свойства файла
-
Путь к файлу: абсолютный и относительный
-
Операции с файлами
-
Виды файлов
-
-
Файловый объект в Python
-
Работа с файлами в Python
-
Основные свойства и методы
-
Простое чтение и запись
-
Чтение файла целиком
-
-
Сериализация и десериализация
-
Модуль
pickle
-
Популярные форматы файлов
-
CSV
-
JSON
-
-
8.1.1. Файлы и файловая система¶
Файл (англ. File) — именованная область данных на носителе информации.
Файлы хранятся в файловой системе — каталоге, определяющим способ организации, хранения и именования данных, а также задающем ограничения на формат и доступ к данным. На сегодняшний день наиболее популярными являются древовидные каталоги (также директории или папки) — файлы, содержащие записи о входящих в них файлах (Рисунок 8.1.1).
Рисунок 8.1.1 — Пример древовидной организации файловой системы в ОС Windows 6.¶
Файловая система связывает носитель информации с одной стороны и программный интерфейс для доступа к файлам — с другой. Когда прикладная программа обращается к файлу, она не имеет никакого представления о том, каким образом расположена информация в конкретном файле, так же как и на каком физическом типе носителя (CD, жестком диске, магнитной ленте, блоке флеш-памяти или другом) он записан. Все, что знает программа — это имя файла, его размер и атрибуты (получая их от драйвера файловой системы). Именно файловая система устанавливает, где и как будет записан файл на физическом носителе (например, жестком диске) (Рисунок 8.1.2).
Рисунок 8.1.2 — Файловая система предоставляет интерфейс доступа к файлам для операционной системы 7¶
8.1.1.1. Свойства файла¶
Файл может обладать различным набором свойств в зависимости от файловой системы.
В большинстве файловых систем файл имеет следующие свойства:
-
имя и расширение (как правило, называемые просто именем вместе): например,
моя_программа.py
; -
дата/время (могут быть предусмотрены маркеры создания, модификации и последнего доступа);
-
владелец;
-
атрибуты (скрытый, системный и др.) и права доступа.
Имя файла имеет определенные ограничения в зависимости от файловой и операционной системы, в частности, допустимые знаки и длину наименования. Расширение указывается после имени через точку, имея назначение, в основном, для ОС Windows, где определяет приложение для запуска файла.
8.1.1.2. Путь к файлу: абсолютный и относительный¶
Для того, чтобы найти файл в файловой системе необходимо знать к нему путь — узлы дерева файловой системы, которые нужно пройти, чтобы до него добраться.
В операционных системах UNIX разделительным знаком при записи пути является /
, в Windows — \
: эти знаки служат для разделения названия каталогов, составляющих путь к файлу.
Путь может быть:
-
абсолютным (полным): указывает на одно и то же место в файловой системе вне зависимости от текущей рабочей директории или других обстоятельств;
-
относительным: путь по отношению к текущему рабочему каталогу пользователя или активных приложений.
Примеры путей для ОС Windows и UNIX:
-
ОС Windows:
-
абсолютный:
C:\user\python\example1.py
; -
относительный:
example1.py
если текущий каталогC:\user\python\
; -
относительный:
python\example1.py
если текущий каталогC:\user\
;
-
-
ОС UNIX:
-
абсолютный:
/home/user/python/example1.py
; -
относительный:
example1.py
если текущий каталог/home/user/python/
; -
относительный:
user/python/example1.py
если текущий каталог/home/
.
-
8.1.1.3. Операции с файлами¶
Все операции с файлами можно подразделить на 2 группы:
-
связанные с его открытием: открытие, закрытие файла, запись, чтение, перемещение по файлу и др.
-
выполняющиеся без его открытия: работа с файлом как элементом файловой системы — переименование, копирование, получение атрибутов и др.
При открытии файла, как правило, указываются:
-
имя файла;
-
права доступа
после чего операционная система возвращает специальный дескриптор файла (идентификатор), однозначно определяющий, с каким файлом далее будут выполняться операции. После открытия доступен файловый указатель — число, определяющее позицию относительно начала файла.
8.1.1.4. Виды файлов¶
По способу организации файлы делятся на файлы с последовательным и произвольным доступом (Рисунок 8.1.3, Таблица 8.1.1).
Рисунок 8.1.3 — Файлы с последовательным и произвольным доступом 8¶
№ |
Характеристика |
Последовательный доступ |
Произвольный доступ |
---|---|---|---|
1 |
Метафора |
|
|
2 |
Как хранят информацию? |
В неструктурированном виде (текстовом) |
В структурированном виде (двоичном) |
2 |
Поиск |
Для поиска или обращения к определенному участку в файле необходимо его последовательно прочитать с начала |
Разрешен непосредственный переход к любой из записи |
3 |
Можно править в текстовом редакторе? |
Да |
Нет, необходима специальная программа |
4 |
Плюсы |
Компактность |
Скорость доступа |
5 |
Основное применение |
Файлы конфигурации, документы |
Файлы баз данных и их производные |
6 |
Пример |
Текстовый файл ( |
База данных ( |
8.1.2. Файловый объект в Python¶
В Python работа с файлами осуществляется через специальный абстрактный файловый объект. В зависимости от способа создания такого объекта, он может быть привязан как к физическому файлу на диске, так и другому устройству, поддерживающему схожие операции (стандартный ввод/вывод и пр.).
Стандартный способ создания файлового объекта — функция open()
:
-
open
(file, mode=‘r’, buffering=— 1, encoding=None, errors=None, newline=None, closefd=True, opener=None)¶ -
Открывает файл и возвращает файловый объект. Если файл не может быть открыт, возбуждается исключение
OSError
и его потомки (FileNotFoundError
и др.).Некоторые из параметров:
- Параметры
-
-
file – путь к файлу (например, строка) или файловый дескриптор;
-
mode –
режим открытия файла:
Символ
Описание
'r'
Открыть для чтения (по умолчанию)
'w'
Открыть для записи (если файл существует, то очищается)
'x'
Открыть для создания с эксклюзивными правами (ошибка, если файл существует)
'a'
Открыть для добавления (если файл существует)
'+'
Открыть для чтения и записи
't'
Текстовый режим (по умолчанию)
'b'
Двоичный режим
Двоичный/текстовый режимы могут быть скомбинированы с другими: например, режим
'rb'
позволит открыть на чтение бинарный файл; -
encoding – наименование кодировки, используемой при чтении/записи файла (например,
'utf-8'
); параметр имеет смысл только для текстового режима.
-
Предупреждение
Кодировка файла
При открытии файла Python по умолчанию использует кодировку, предпочитаемую операционной системой. Для определения кодировки по умолчанию выполните код:
import locale locale.getpreferredencoding(False) # 'cp1251' на российской сборке ОС Windows
Старайтесь указывать кодировку файла явно, например, encoding="utf-8"
, особенно если есть вероятность работы программы на различных ОС.
Открытие файлов связано с потреблением/резервированием ресурсов, поэтому после выполнения необходимых операций его следует закрыть.
-
class
file
¶ -
-
close
()¶ -
Закрывает файл. После этого работа с файлом невозможна (чтение, запись и др.).
-
Общий цикл работы с файлом может выглядеть следующим образом (Листинг 8.1.1).
Листинг 8.1.1 — Пример цикла работы с файлом | скачать
¶
# При работе с файлами всегда целесообразно использовать исключения # 1. Стандартный способ открытия файла с обработкой исключений fh = None try: fh = open("data.txt", encoding="utf-8") # # Чтение и запись файла # except Exception as e: print("Ошибка при работе с файлом:", e) finally: if fh: # Если файл не открылся, значит 'fh' == None и закрывать его не нужно fh.close() # 2. Для упрощения кода по выделению и высвобождению ресурсов в Python # предусмотрены специальные объекты - менеджеры контекста, # которые могут самостоятельно следить за использованием ресурсов # # Наиболее часто менеджеры контекста вызываются с использованием ключевого слова with try: with open("data2.txt", encoding="utf-8") as fh: # # Чтение и запись файла # except Exception as e: print("Ошибка при работе с файлом:", e)
Примечание
В большинстве примеров данной темы подробная обработка исключений опущена для того, чтобы сосредоточиться на демонстрации конкретных возможностей.
При самостоятельном написании программ не следует забывать добавлять обработку исключений — программа должна адекватно реагировать на возможные нестандартные ситуации (используемые файлы может изменить пользователь или другая программа).
8.1.3. Работа с файлами в Python¶
8.1.3.1. Основные свойства и методы¶
Файловый объект предоставляет ряд свойств и методов для работы с файлами. Большинство методов универсально и предполагают работу (чтение/запись) со строками в указанной кодировке (str
для текстовых файлов) или с набором байт (bytes
для двоичных файлов).
-
class
file
¶ -
-
name
¶ -
Имя файла (если имеется).
-
mode
¶ -
Режим, в котором был открыт файл.
-
encoding
¶ -
Кодировка, используемая для строковых преобразований в файле.
-
closed
¶ -
Возвращает
True
, если файл закрыт.
-
close
()¶ -
Закрывает файл. После этого работа с файлом невозможна (чтение, запись и др.).
-
read
(count)¶ -
Читает до
count
байт из файлового объекта. Если значениеcount
не определено, то читаются все байты, начиная от текущей позиции и до конца.Если ничего не было прочитано (конец файла), возвращается пустой объект
str
илиbytes
.
-
readinto
(ba)¶ -
Читает до
len(ba)
байт в объектba
типаbytearray
и возвращает число прочитанных байт (0, если был достигнут конец файла).Доступен только в двоичном режиме.
-
readline
(count)¶ -
Читает следующую строку (до
count
байт, если значениеcount
определено и число прочитанных байтов было достигнуто раньше, чем встретился символ перевода строки'\n'
), включая символ перевода строки'\n'
.
-
readlines
(sizehint)¶ -
Читает все строки до конца файла и возвращает их в виде списка.
Если значение аргумента
sizehint
определено, то будет прочитано примерноsizehint
байт (если файл поддерживает такую возможность).
-
write
(s)¶ -
Записывает в файл объект
s
типа:-
str
для текстового режима; -
bytes
/bytearray
для двоичного режима.
Примечание
Запись в файл возможна и с помощью стандартной функции
print()
, установив ключевой параметрfile
в открытый файловый объект. -
-
writelines
(seg)¶ -
Записывает в файл последовательность объектов типа:
-
str
для текстового режима; -
bytes
/bytearray
для двоичного режима.
-
-
flush
()¶ -
При работе с файлами Python по умолчанию использует буфер определенного размера. Вызов методов записи приводит к записи в буфер, после чего в определенный момент производится очистка буфера и передача сигнала для записи данных на диск.
Метод
flush()
вызывает принудительное очистку буфера. В большинстве случаев вызывать его напрямую не нужно.
-
close
()¶ -
Закрывает файл. После этого работа с файлом невозможна (чтение, запись и др.).
-
8.1.3.2. Простое чтение и запись¶
В Листинге 8.1.2 приведен пример работы с двоичным файлом.
Листинг 8.1.2 — Пример работы с двоичным файлом | скачать
¶
human = dict(name="Михаил Толстых", age=35, weight=90.5) filename = "08_01_02_data.txt" # 1. Запись в файл # При записи бинарных файлов все данные должны быть преобразованы в тип bytes # Удобно выполнить преобразование через метод str.encode() fh = None try: fh = open(filename, "wb") fh.write(bytes(human["name"].encode("utf-8"))) fh.write(bytes(str(human["age"]).encode("utf-8"))) fh.write(bytes(str(human["weight"]).encode("utf-8"))) finally: if fh: fh.close() # 2. Чтение из файла # При чтении бинарных файлов необходимо точно знать, сколько байт # прочитать и как их декодировать, используя bytes.decode() # При редактировании файла в стороннем редакторе файл может быть не читаем fh = None try: fh = open(filename, "rb") name = fh.read(27).decode("utf-8") age = int(fh.read(2).decode("utf-8")) weight = float(fh.read(4).decode("utf-8")) print(name, age, weight) # Михаил Толстых 35 90.5 finally: if fh: fh.close()
В Листинге 8.1.3 приведен пример работы с текстовым файлом.
Листинг 8.1.3 — Пример работы с текстовым файлом | скачать
¶
human = dict(name="Михаил Толстых", age=35, weight=90.5) filename = "08_01_03_data.txt" # 1. Запись в файл # При записи текстовых файлов все данные должны быть преобразованы в тип str # По умолчанию, write() не добавляет перенос строки, однако его можно добавить самостоятельно fh = None try: fh = open(filename, "w", encoding="utf-8") # При добавлении переноса записываемые данные будут на отдельной строке fh.write(human["name"] + "\n") fh.write(str(human["age"]) + "\n") # Как альтернатива - print() позволяет не переводить в строку и не добавлять перенос вручную print(human["weight"], file=fh) finally: if fh: fh.close() # 2. Чтение из файла # Для чтения отдельной строки достаточно вызвать метод readline(). # В конце полученной строки знак переноса - \n, # который можно убрать, например, методом str.strip() fh = None try: fh = open(filename, encoding="utf-8") # Читаем первые 3 строки и преобразуем при необходимости name = fh.readline().strip() age = int(fh.readline()) weight = float(fh.readline()) print(name, age, weight) # Михаил Толстых 35 90.5 finally: if fh: fh.close()
8.1.3.3. Чтение файла целиком¶
Чтение файла, приведенное в Листинге 8.1.3 не подразумевает, что содержимое файла может меняться.
Учитывать такие изменения можно, прочитав файл целиком:
-
в одну строку;
-
в список строк;
-
построчно, пока не достигнут конец файла.
Примеры реализации данных вариантов приведены в Листинге 8.1.4 на примере файла 08_01_04_data.txt
:
Содержимое файла 08_01_04_data.txt
| скачать
¶
Когда дети будут смотреть на великих учёных так же, как они смотрят на знаменитых актёров и музыкантов, человечество совершит большой прорыв. Брайан Грин https://ru.wikipedia.org/wiki/Грин,_Брайан_Рэндолф
Листинг 8.1.4 — Различные способы чтения текстового файла целиком | скачать
¶
filename = "08_01_04_data.txt" # В данном примере обработка исключений не приводится, чтобы # сосредоточить внимание на чтении файлов # 1. Чтение из файла (в одну строку) with open(filename, encoding="utf-8") as fh: data = fh.read() print(data) # 2. Чтение из файла (в список) with open(filename, encoding="utf-8") as fh: data = fh.readlines() print(data) # ['Когда дети будут смотреть на великих учёных так же,\n', # 'как они смотрят на знаменитых актёров и музыкантов,\n', # 'человечество совершит большой прорыв.\n', # '\n', # 'Брайан Грин\n', # 'https://ru.wikipedia.org/wiki/Грин,_Брайан_Рэндолф\n'] # 3. Чтение из файла (построчно) with open(filename, encoding="utf-8") as fh: for line in fh: print(line.strip())
8.1.4. Сериализация и десериализация¶
Чтение/запись простых типов (например, чисел или строк) не представляет большого труда, однако с увеличением объема информации появляется необходимость эффективно сохранять/загружать более сложные структуры данных (например, словари). Кроме того, модульная архитектура современного программного обеспечения приводит к необходимости обмена данными между различными модулями, а также между приложениями в целом, для чего необходимо иметь возможность удобно обмениваться данными.
Сериализация — процесс перевода какой-либо структуры данных в последовательность битов. Десериализация — обратный процесс.
Чаще всего сериализация используется для сохранения объектов в файлы или передачи их по сети.
8.1.4.1. Модуль pickle
¶
Одним из способов, позволяющих сериализовать/десериализовать данные в Python, является использование стандартного модуля pickle
, при помощи которого можно сохранять любой объект Python в двоичном файле, а затем извлекать его обратно.
Основные функции модуля:
-
pickle.
dump
(obj, file, protocol=None, *, fix_imports=True)¶ -
Сериализует объект
obj
и записывает его в файлfile
.Некоторые из параметров:
- Параметры
-
-
obj – объект для записи;
-
file – файловый объект;
-
protocol – версия формата
pickle
.
-
-
pickle.
load
(file, *, fix_imports=True, encoding=‘ASCII’, errors=‘strict’)¶ -
Читает и десериализует содержимое файла
file
, возвращая созданный объект (структуру).Некоторые из параметров:
- Параметры
-
file – файловый объект.
Пример работы с модулем pickle
приведен в Листинге 8.1.5.
Листинг 8.1.5 — Использование pickle
для загрузки/сохранения объектов Python | скачать
¶
import pickle filename = "08_01_05_data.txt" # список покупок shoplist = {"фрукты": ["яблоки", "манго"], "овощи": ["морковь"], "бюджет": 1000} # Запись в файл with open(filename, "wb") as fh: pickle.dump(shoplist, fh) # помещаем объект в файл # Считываем из хранилища shoplist_2 = [] with open(filename, "rb") as fh: shoplist_2 = pickle.load(fh) # загружаем объект из файла print(shoplist_2) # {'бюджет': 1000, 'овощи': ['морковь'], 'фрукты': ['яблоки', 'манго']}
Формат файла, создаваемого pickle
, приведен на Рисунке 8.1.4.
Рисунок 8.1.4 — Содержимое файла с данными при использовании pickle
(в редакторе Notepad++)¶
Минусы формата pickle
:
-
специфичен для Python (не может быть использован, если файл будет читаться с использованием других языков программирования);
-
небезопасен (десериализация готовых конструкций языка может привести к выполнению ненадежного кода).
8.1.4.2. Популярные форматы файлов¶
Большое количество данных в совокупности с их разнородностью привело к появлению специальных форматов файлов, позволяющих хранить различные объемы связанной информации и не привязанных к конкретному языку программирования.
Среди них одними из наиболее популярных являются:
-
CSV (англ. Comma-Separated Values — значения, разделенные запятыми);
-
JSON (англ. JavaScript Object Notation) — текстовый формат обмена данными, основанный на JavaScript;
-
XML (англ. eXtensible Markup Language — расширяемый язык разметки);
-
YAML (англ. YAML Ain’t Markup Language — «YAML — Не язык разметки»);
-
INI (англ. Initialization file — файл инициализации);
-
и др.
Подавляющее большинство форматов поддерживается Python (стандартными или сторонними модулями и пакетами).
8.1.4.2.1. CSV¶
CSV (англ. Comma-Separated Values — значения, разделенные запятыми, 2005 г.) — текстовый формат, предназначенный для представления табличных данных. Каждая строка файла — это одна строка таблицы, где значения отдельных колонок разделяются разделительным символом (англ. delimiter) запятой ,
и заключаются в кавычки "
(Рисунок 8.1.5).
Несмотря на наличие стандарта (RFC 4180), на сегодняшний день под CSV, как правило, понимают набор значений, разделенных произвольными разделителями, в произвольной кодировке с произвольными окончаниями строк. Это значительно затрудняет перенос данных из одних программ в другие, несмотря на всю простоту реализации поддержки CSV (так, например, Microsoft Excel не всегда открывает стандартные разделенные запятыми данные).
В Python работа с CSV-файлами поддерживается стандартным модулем csv
, предоставляющем следующие основные объекты и функции:
-
csv.
reader
(csvfile, dialect=‘excel’, **fmtparams)¶ -
Создает и возвращает объект для чтения последовательности из CSV-файла.
Некоторые из параметров:
- Параметры
-
-
csvfile – итерируемый объект, возвращающий строку на каждой итерации (например, файловый объект в текстовом режиме доступа);
-
dialect – диалект CSV (набор специальных параметров);
-
fmtparams – дополнительные настройки (совокупность кавычек, разделителей и т.д.).
-
-
csv.
writer
(csvfile, dialect=‘excel’, **fmtparams)¶ -
Создает и возвращает объект для записи последовательности в CSV-файл.
Некоторые из параметров:
- Параметры
-
-
csvfile – любой объект, поддерживающий метод записи
write()
; -
dialect – аналогично
csv.reader()
; -
fmtparams – аналогично
csv.reader()
.
-
-
class
csv.
DictReader
(csvfile, fieldnames=None, restkey=None, restval=None, dialect=‘excel’, *args, **kwds)¶ -
Создает и возвращает объект для чтения данных из CSV-файла как словаря значений.
Некоторые из параметров:
- Параметры
-
-
csvfile – итерируемый объект, возвращающий строку на каждой итерации (например, файловый объект в текстовом режиме доступа);
-
fieldnames – список наименований столбцов (если не задан, используется первая строка файла).
-
-
class
csv.
DictWriter
(csvfile, fieldnames, restval=», extrasaction=‘raise’, dialect=‘excel’, *args, **kwds)¶ -
Создает и возвращает объект для записи данных как словаря значений в CSV-файл.
Некоторые из параметров:
- Параметры
-
-
csvfile – любой объект, поддерживающий метод записи
write()
; -
fieldnames – список наименований столбцов.
-
-
class
csv.
Writer
¶ -
-
writerow
(row)¶ -
Записывает последовательность
row
в CSV-файл.
-
writerows
(rows)¶ -
Записывает список последовательностей
rows
в CSV-файл.
-
-
class
csv.
DictWriter
¶ -
-
Записывает в файл заголовки файла, переданные при создании класса.
-
writerow
(row)¶ -
Записывает словарь
row
в CSV-файл.
-
writerows
(rows)¶ -
Записывает список словарей
rows
в CSV-файл.
-
-
exception
csv.
Error
¶ -
Класс исключения, возбуждаемый при ошибке в работе любой из функций модуля.
Пример использования модуля csv
приведен в Листинге 8.1.6 (а-б).
Листинг 8.1.6 (а) — Работа с CSV-файлом в Python (последовательность) | скачать
¶
import csv filename = "08_01_06_a_data.csv" # список покупок shoplist = {"яблоки": [2, 100], "манго": [3, 250], "морковь": [1, 35]} # Запись в файл with open(filename, "w", encoding="utf-8", newline="") as fh: writer = csv.writer(fh, quoting=csv.QUOTE_ALL) writer.writerow(["Наименование", "Вес", "Цена/кг."]) # Заголовки столбца for name, values in sorted(shoplist.items()): writer.writerow([name, *values]) writer.writerow(["рис", "4", "70"]) # Допишем произвольную запись # Содержимое файла # # "Наименование","Вес","Цена/кг." # "манго","3","250" # "морковь","1","35" # "яблоки","2","100" # "рис","4","70" # Чтение файла rows = [] with open(filename, "r", encoding="utf-8") as fh: reader = csv.reader(fh) rows = list(reader) # reader - итерируемый объект и может быть преобразован в список строк for row in rows: print(row) # Вывод на экран # # ['Наименование', 'Вес', 'Цена/кг.'] # ['манго', '3', '250'] # ['морковь', '1', '35'] # ['яблоки', '2', '100'] # ['рис', '4', '70']
Листинг 8.1.6 (б) — Работа с CSV-файлом в Python (словарь) | скачать
¶
import csv filename = "08_01_06_b_data.csv" # список покупок shoplist = {"яблоки": [2, 100], "манго": [3, 250], "морковь": [1, 35]} # Запись в файл with open(filename, "w", encoding="utf-8", newline="") as fh: writer = csv.DictWriter(fh, fieldnames=["name", "weight", "price"], quoting=csv.QUOTE_ALL) writer.writeheader() # Записывает заголовки в файл for name, values in sorted(shoplist.items()): writer.writerow(dict(name=name, weight=values[0], price=values[1])) # Содержимое файла # # "name","weight","price" # "манго","3","250" # "морковь","1","35" # "яблоки","2","100" # Чтение файла rows = [] with open(filename, "r", encoding="utf-8") as fh: reader = csv.DictReader(fh) rows = list(reader) # reader - итерируемый объект и может быть преобразован в список строк for row in rows: print(row) # Вывод на экран # # {'name': 'манго', 'weight': '3', 'price': '250'} # {'name': 'морковь', 'weight': '1', 'price': '35'} # {'name': 'яблоки', 'weight': '2', 'price': '100'}
8.1.4.2.2. JSON¶
JSON (англ. JavaScript Object Notation, 1999 г.) — текстовый формат обмена данными, основанный на JavaScript. Одно из преимуществ — JSON легко читается людьми (англ. human-readable) (Листинг 8.1.7).
Листинг 8.1.7 — Пример JSON-файла | скачать
¶
{ "ФИО": "Иванов Сергей Михайлович", "ЕГЭ": { "Математика": 90, "Физика": 70, "Информатика": 80 }, "Хобби": ["Рисование", "Плавание"], "Возраст": 25.5, "ДомЖивотные": null }
JSON-текст представляет собой одну из двух структур:
-
набор пар
ключ: значение
(словарь в терминологии Python), где ключ — строка, значение — любой тип; -
упорядоченный набор значений (список в терминологии Python).
Значением может являться:
-
строка (в кавычках);
-
число;
-
логическое значение (
true
/false
); -
null
; -
одна из структур.
Одним из преимуществ JSON является близкое соответствие Python по типам данных. Работа с JSON-форматом поддерживается стандартным пакетом json
, предоставляющем следующие основные функции:
-
json.
dumps
(obj, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)¶ -
Сериализует объект
obj
, возвращая строку в JSON-формате.Некоторые из параметров:
- Параметры
-
-
obj – сериализуемый объект;
-
ensure_ascii – если равен
False
, запись не-ASCII значений происходит в файл «как есть», без преобразования в Unicode; -
indent – величина отступа для вложенных структур.
-
-
json.
loads
(s, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)¶ -
Десериализует объект (в том числе файловый)
s
, возвращая структуру в Python.При ошибке десериализации возбуждается исключение JSONDecodeError.
-
exception
json.
JSONDecodeError
(msg, doc, pos, end=None)¶ -
Класс исключения, возбуждаемый при ошибке в работе некоторых функций пакета.
Пример работы с JSON-форматом приведен в Листинге 8.1.8.
Листинг 8.1.8 — Работа с JSON-форматом в Python | скачать
¶
import json filename = "08_01_08_data.json" info = { "ФИО": "Иванов Сергей Михайлович", "ЕГЭ": { "Математика": 90, "Физика": 70, "Информатика": 80 }, "Хобби": ["Рисование", "Плавание"], "Возраст": 25.5, "ДомЖивотные": None } # Запись структуры в файл в JSON-формате with open(filename, "w", encoding="utf-8") as fh: fh.write(json.dumps(info, ensure_ascii=False, indent=4)) # Пример содержимого файла: # { # "Хобби": [ # "Рисование", # "Плавание" # ], # "ЕГЭ": { # "Информатика": 80, # "Математика": 90, # "Физика": 70 # }, # "ФИО": "Иванов Сергей Михайлович", # "ДомЖивотные": null, # "Возраст": 25.5 # } # Чтение из файла JSON-формата info_2 = [] with open(filename, encoding="utf-8") as fh: info_2 = json.loads(fh.read()) print(info_2) # {'ФИО': 'Иванов Сергей Михайлович', 'ЕГЭ': {'Информатика': 80, 'Математика': 90, 'Физика': 70}, # 'Хобби': ['Рисование', 'Плавание'], 'Возраст': 25.5, 'ДомЖивотные': None}
Примечание
Валидация и оформление JSON-файлов
При возникновении ошибки чтения файла JSON-формата рекомендуется проверить его синтаксис с использованием специальных онлайн-сервисов, например, https://jsonformatter.curiousconcept.com/, которые могут как указать место ошибки, так и оформить его по стандарту.
- 1
-
Sebesta, W.S Concepts of Programming languages. 10E; ISBN 978-0133943023.
- 2
-
Python — официальный сайт. URL: https://www.python.org/.
- 3
-
Python — FAQ. URL: https://docs.python.org/3/faq/programming.html.
- 4
-
Саммерфилд М. Программирование на Python 3. Подробное руководство. — М.: Символ-Плюс, 2009. — 608 с.: ISBN: 978-5-93286-161-5.
- 5
-
Лучано Рамальо. Python. К вершинам мастерства. — М.: ДМК Пресс , 2016. — 768 с.: ISBN: 978-5-97060-384-0, 978-1-491-94600-8.
- 6
-
Что такое папка. URL: http://beginpc.ru/windows/chto-takoe-folder.
- 7
-
The Volume Does Not Contain A Recognized File System – How To Fix. URL: https://www.powerdatarecovery.com/hard-drive-recovery/volume-not-contain-recognized-file-system.html.
- 8
-
Последовательный доступ. URL: https://ru.wikipedia.org/wiki/Последовательный_доступ.