Шаг 159.
Основы языка 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 "<pyshell#3>", line 1, in <module>
    open("C:\temp\new\file.txt")
OSError: [Errno 22] Invalid argument: 'C:\temp\new\x0cile.txt'

    Вместо абсолютного пути к файлу можно указать относительный путь. В этом случае путь определяется с учетом местоположения текущего рабочего каталога. Относительный путь будет автоматически преобразован в абсолютный путь с помощью функции abspath () из модуля os.path. Возможны следующие варианты:

    Как можно видеть, в абсолютном и относительном путях можно указать как прямые, так и обратные слеши. Все они будут автоматически преобразованы с учетом значения атрибута 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().




Предыдущий шаг Содержание Следующий шаг