Рубрики
Без рубрики

os.path – независимое от платформы манипулирование именами файлов

Автор оригинала: Doug Hellmann.

Цель:

Разбирайте, создавайте, тестируйте и иначе работайте с именами файлов и путями.

Написать код для работы с файлами на нескольких платформах легко с помощью функций, включенных в модуль os.path . Даже программы, не предназначенные для переноса между платформами, должны использовать os.path для надежного анализа имени файла.

Парсинг путей

Первый набор функций в os.path может использоваться для синтаксического анализа строк, представляющих имена файлов, на их составные части. Важно понимать, что эти функции не зависят от реально существующих путей; они действуют исключительно на струнах.

Анализ пути зависит от нескольких переменных, определенных в os:

  • os.sep – разделитель между частями пути (например, «/» или « \ »).
  • os.extsep – разделитель между именем файла и “расширением” файла (например, “. “).
  • os.pardir – компонент пути, который означает переход по дереву каталогов на один уровень вверх (например, « .. »).
  • os.curdir – компонент пути, который ссылается на текущий каталог (например, «. »).

Функция split () разбивает путь на две отдельные части и возвращает кортеж с результатами. Второй элемент tuple – это последний компонент пути, а первый элемент – это все, что предшествует ему.

ospath_split.py

import os.path

PATHS  [
    '/one/two/three',
    '/one/two/three/',
    '/',
    '.',
    '',
]

for path in PATHS:
    print('{!r:>17} : {}'.format(path, os.path.split(path)))

Когда входной аргумент заканчивается на os.sep , последний элемент пути является пустой строкой.

$ python3 ospath_split.py

 '/one/two/three' : ('/one/two', 'three')
'/one/two/three/' : ('/one/two/three', '')
              '/' : ('/', '')
              '.' : ('', '.')
               '' : ('', '')

Функция basename () возвращает значение, эквивалентное второй части значения split () .

ospath_basename.py

import os.path

PATHS  [
    '/one/two/three',
    '/one/two/three/',
    '/',
    '.',
    '',
]

for path in PATHS:
    print('{!r:>17} : {!r}'.format(path, os.path.basename(path)))

Полный путь сокращается до последнего элемента, независимо от того, относится ли он к файлу или каталогу. Если путь заканчивается разделителем каталогов ( os.sep ), базовая часть считается пустой.

$ python3 ospath_basename.py

 '/one/two/three' : 'three'
'/one/two/three/' : ''
              '/' : ''
              '.' : '.'
               '' : ''

Функция dirname () возвращает первую часть разделенного пути:

ospath_dirname.py

import os.path

PATHS  [
    '/one/two/three',
    '/one/two/three/',
    '/',
    '.',
    '',
]

for path in PATHS:
    print('{!r:>17} : {!r}'.format(path, os.path.dirname(path)))

Объединение результатов basename () с dirname () дает исходный путь.

$ python3 ospath_dirname.py

 '/one/two/three' : '/one/two'
'/one/two/three/' : '/one/two/three'
              '/' : '/'
              '.' : ''
               '' : ''

splitext () работает аналогично split () , но разделяет путь по разделителю расширения, а не по разделителю каталогов.

ospath_splitext.py

import os.path

PATHS  [
    'filename.txt',
    'filename',
    '/path/to/filename.txt',
    '/',
    '',
    'my-archive.tar.gz',
    'no-extension.',
]

for path in PATHS:
    print('{!r:>21} : {!r}'.format(path, os.path.splitext(path)))

При поиске расширения используется только последнее вхождение os.extsep , поэтому, если имя файла имеет несколько расширений, в результате разделения остается часть расширения на префиксе.

$ python3 ospath_splitext.py

       'filename.txt' : ('filename', '.txt')
           'filename' : ('filename', '')
'/path/to/filename.txt' : ('/path/to/filename', '.txt')
                  '/' : ('/', '')
                   '' : ('', '')
  'my-archive.tar.gz' : ('my-archive.tar', '.gz')
      'no-extension.' : ('no-extension', '.')

commonprefix () принимает список путей в качестве аргумента и возвращает единственную строку, представляющую общий префикс, присутствующий во всех путях. Значение может представлять путь, который на самом деле не существует, и разделитель путей не учитывается, поэтому префикс может не останавливаться на границе разделителя.

ospath_commonprefix.py

import os.path

paths  ['/one/two/three/four',
         '/one/two/threefold',
         '/one/two/three/',
         ]
for path in paths:
    print('PATH:', path)

print()
print('PREFIX:', os.path.commonprefix(paths))

В этом примере общая строка префикса – /one/two/three , хотя один путь не включает каталог с именем three .

$ python3 ospath_commonprefix.py

PATH: /one/two/three/four
PATH: /one/two/threefold
PATH: /one/two/three/

PREFIX: /one/two/three

commonpath () учитывает разделители путей и возвращает префикс, который не включает частичные значения пути.

ospath_commonpath.py

import os.path

paths  ['/one/two/three/four',
         '/one/two/threefold',
         '/one/two/three/',
         ]
for path in paths:
    print('PATH:', path)

print()
print('PREFIX:', os.path.commonpath(paths))

Поскольку "тройной" не имеет разделителя пути после "три" , общий префикс – /one/two .

$ python3 ospath_commonpath.py

PATH: /one/two/three/four
PATH: /one/two/threefold
PATH: /one/two/three/

PREFIX: /one/two

Строительные пути

Помимо разделения существующих путей, часто необходимо построить пути из других строк. Чтобы объединить несколько компонентов пути в одно значение, используйте join () :

ospath_join.py

import os.path

PATHS  [
    ('one', 'two', 'three'),
    ('/', 'one', 'two', 'three'),
    ('/one', '/two', '/three'),
]

for parts in PATHS:
    print('{} : {!r}'.format(parts, os.path.join(*parts)))

Если какой-либо аргумент для соединения начинается с os.sep , все предыдущие аргументы отбрасываются, а новый становится началом возвращаемого значения.

$ python3 ospath_join.py

('one', 'two', 'three') : 'one/two/three'
('/', 'one', 'two', 'three') : '/one/two/three'
('/one', '/two', '/three') : '/three'

Также можно работать с путями, которые включают «переменные» компоненты, которые могут быть расширены автоматически. Например, expanduser () преобразует символ тильды ( ~ ) в имя домашнего каталога пользователя.

ospath_expanduser.py

import os.path

for user in ['', 'dhellmann', 'nosuchuser']:
    lookup  '~' + user
    print('{!r:>15} : {!r}'.format(
        lookup, os.path.expanduser(lookup)))

Если домашний каталог пользователя не может быть найден, строка возвращается без изменений, как в случае с ~ nosuchuser в этом примере.

$ python3 ospath_expanduser.py

            '~' : '/Users/dhellmann'
   '~dhellmann' : '/Users/dhellmann'
  '~nosuchuser' : '~nosuchuser'

expandvars () является более общим и расширяет любые переменные среды оболочки, присутствующие в пути.

ospath_expandvars.py

import os.path
import os

os.environ['MYVAR']  'VALUE'

print(os.path.expandvars('/path/to/$MYVAR'))

Проверка не выполняется, чтобы гарантировать, что значение переменной приводит к имени уже существующего файла.

$ python3 ospath_expandvars.py

/path/to/VALUE

Нормализация путей

Пути, собранные из отдельных строк с помощью join () или со встроенными переменными, могут закончиться дополнительными разделителями или компонентами относительного пути. Используйте normpath () , чтобы очистить их:

ospath_normpath.py

import os.path

PATHS  [
    'one//two//three',
    'one/./two/./three',
    'one/../alt/two/three',
]

for path in PATHS:
    print('{!r:>22} : {!r}'.format(path, os.path.normpath(path)))

Сегменты пути, состоящие из os.curdir и os.pardir , оцениваются и сворачиваются.

$ python3 ospath_normpath.py

     'one//two//three' : 'one/two/three'
   'one/./two/./three' : 'one/two/three'
'one/../alt/two/three' : 'alt/two/three'

Чтобы преобразовать относительный путь в абсолютное имя файла, используйте abspath () .

ospath_abspath.py

import os
import os.path

os.chdir('/usr')

PATHS  [
    '.',
    '..',
    './one/two/three',
    '../one/two/three',
]

for path in PATHS:
    print('{!r:>21} : {!r}'.format(path, os.path.abspath(path)))

В результате получается полный путь, начинающийся с вершины дерева файловой системы.

$ python3 ospath_abspath.py

                  '.' : '/usr'
                 '..' : '/'
    './one/two/three' : '/usr/one/two/three'
   '../one/two/three' : '/one/two/three'

Файловое время

Помимо работы с путями, os.path включает функции для получения свойств файла, аналогичные тем, которые возвращает os.stat () :

ospath_properties.py

import os.path
import time

print('File         :', __file__)
print('Access time  :', time.ctime(os.path.getatime(__file__)))
print('Modified time:', time.ctime(os.path.getmtime(__file__)))
print('Change time  :', time.ctime(os.path.getctime(__file__)))
print('Size         :', os.path.getsize(__file__))

os.path.getatime () возвращает время доступа, os.path.getmtime () возвращает время модификации, а os.path.getctime () возвращает время создания. os.path.getsize () возвращает количество данных в файле, представленное в байтах.

$ python3 ospath_properties.py

File         : ospath_properties.py
Access time  : Sun Mar 18 16:21:22 2018
Modified time: Fri Nov 11 17:18:44 2016
Change time  : Fri Nov 11 17:18:44 2016
Size         : 481

Тестирование файлов

Когда программа встречает имя пути, ей часто необходимо знать, относится ли этот путь к файлу, каталогу или символической ссылке и существует ли он. os.path включает функции для проверки всех этих условий.

ospath_tests.py

import os.path

FILENAMES  [
    __file__,
    os.path.dirname(__file__),
    '/',
    './broken_link',
]

for file in FILENAMES:
    print('File        : {!r}'.format(file))
    print('Absolute    :', os.path.isabs(file))
    print('Is File?    :', os.path.isfile(file))
    print('Is Dir?     :', os.path.isdir(file))
    print('Is Link?    :', os.path.islink(file))
    print('Mountpoint? :', os.path.ismount(file))
    print('Exists?     :', os.path.exists(file))
    print('Link Exists?:', os.path.lexists(file))
    print()

Все тестовые функции возвращают логические значения.

$ ln -s /does/not/exist broken_link
$ python3 ospath_tests.py

File        : 'ospath_tests.py'
Absolute    : False
Is File?    : True
Is Dir?     : False
Is Link?    : False
Mountpoint? : False
Exists?     : True
Link Exists?: True

File        : ''
Absolute    : False
Is File?    : False
Is Dir?     : False
Is Link?    : False
Mountpoint? : False
Exists?     : False
Link Exists?: False

File        : '/'
Absolute    : True
Is File?    : False
Is Dir?     : True
Is Link?    : False
Mountpoint? : True
Exists?     : True
Link Exists?: True

File        : './broken_link'
Absolute    : False
Is File?    : False
Is Dir?     : False
Is Link?    : True
Mountpoint? : False
Exists?     : False
Link Exists?: True

Смотрите также

  • стандартная библиотечная документация для os.path
  • Заметки о переносе Python 2 на 3 для os.path
  • pathlib – Пути как объекты.
  • os – модуль os является родительским для os.path .
  • time – модуль времени включает функции для преобразования между представлением, используемым функциями свойств времени в os.path , и удобными для чтения строками.