os.path — Manipulación de nombres de archivo independiente de la plataforma

Propósito:Analizar, construir, probar y trabajar de otra forma en nombres de archivos y rutas.

Escribir código para trabajar con archivos en múltiples plataformas es fácil usando funciones incluidas en el módulo os.path. Incluso programas no destinados a ser portados entre plataformas deben usar os.path para análisis confiable de nombre de archivo.

Analizando rutas

El primer conjunto de funciones en os.path se puede usar para analizar cadenas que representan nombres de archivo en sus partes componentes. Es importante darse cuenta de que estas funciones no dependen de las rutas existente; operan únicamente en las cadenas.

El análisis de rutas depende de algunas variables definidas en os:

  • os.sep - El separador entre partes de la ruta (por ejemplo, «/» o «\»).
  • os.extsep - El separador entre un nombre de archivo y las «extensión» del archivo (por ejemplo, «.»).
  • os.pardir - El componente de ruta que significa atravesar el árbol de directorios subiendo un nivel (por ejemplo, «..»).
  • os.curdir - El componente de ruta que hace referencia a directorio actual (por ejemplo, «.»).

La función split() divide la ruta en dos partes separadas y devuelve un tuple con los resultados. El segundo elemento del tuple es el último componente de la ruta, y el primer elemento es todo lo que viene antes.

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)))

Cuando el argumento de entrada termina en os.sep, el último elemento de la ruta es una cadena vacía.

$ python3 ospath_split.py

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

La función basename() devuelve un valor equivalente a la segunda parte del valor de 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)))

La ruta completa se reduce al último elemento, si se refiere a un archivo o un directorio. Si la ruta termina en el separador de directorios (os.sep), la parte de base se considera vacía.

$ python3 ospath_basename.py

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

La función dirname() devuelve la primera parte de la ruta:

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)))

La combinación de los resultados de basename() con dirname() da la ruta original.

$ python3 ospath_dirname.py

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

splitext() funciona como split(), pero divide la ruta en el separador de extensiones, en lugar del separador de directorios.

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)))

Solo se utiliza la última aparición de os.extsep al buscar la extensión, por lo que si un nombre de archivo tiene múltiples extensiones los resultados de dividirlo deja parte de la extensión en el prefijo.

$ 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() toma una lista de rutas como un argumento y devuelve una sola cadena que representa un prefijo común presente en todas las rutas. El valor puede representar una ruta que en realidad no existe, y el separador de ruta no está incluido en la consideración, por lo que el prefijo podría no detenerse en un límite separador.

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))

En este ejemplo, la cadena de prefijo común es /one/two/three, incluso cuando una ruta no incluye un directorio llamado three.

$ python3 ospath_commonprefix.py

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

PREFIX: /one/two/three

commonpath() respeta los separadores de ruta y devuelve un prefijo que no incluye valores parciales de ruta.

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))

Porque "threefold" no tiene un separador de ruta después de "three" el prefijo común es /one/two.

$ python3 ospath_commonpath.py

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

PREFIX: /one/two

Cronstruyendo rutas

Además de separar las rutas existentes, con frecuencia es necesario construir rutas desde otras cadenas. Para combinar varios componentes de ruta en un solo valor, usa 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)))

Si algún argumento para unirse comienza con os.sep, todos los argumentos anteriores se descartan y el nuevo se convierte en el comienzo del valor de retorno.

$ python3 ospath_join.py

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

También es posible trabajar con rutas que incluyen componentes «variables» que pueden ser expandidos automáticamente. Por ejemplo, expanduser() convierte el carácter tilde (~) en el nombre del directorio de incio de un usuario.

ospath_expanduser.py
import os.path

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

Si no se puede encontrar el directorio de inicio del usuario, se devuelve la cadena sin cambios, como con ~nosuchuser en este ejemplo.

$ python3 ospath_expanduser.py

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

expandvars() es más general y expande cualquier variable de entorno de shell presentes en la ruta.

ospath_expandvars.py
import os.path
import os

os.environ['MYVAR'] = 'VALUE'

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

No se realiza ninguna validación para garantizar que los resultados del valor de la variable resulta en el nombre de un archivo que ya existe.

$ python3 ospath_expandvars.py

/path/to/VALUE

Normalizando rutas

Rutas ensambladas a partir de cadenas separadas usando join() o con las variables embebidas pueden terminar con separadores adicionales o componentes de ruta relativos. Utiliza normpath() para limpiarlos:

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)))

Los segmentos de ruta compuestos por os.curdir y os.pardir son evaluados y colapsados.

$ python3 ospath_normpath.py

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

Para convertir una ruta relativa a un nombre de archivo absoluto, usa 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)))

El resultado es una ruta completa, comenzando en la parte superior del árbol del sistema de archivos.

$ python3 ospath_abspath.py

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

Tiempos de archivos

Además de trabajar con rutas, os.path incluye funciones para recuperar propiedades de archivo, similares a las devueltas por 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() devuelve el tiempo de acceso, os.path.getmtime() devuelve el tiempo de modificación, y os.path.getctime() devuelve el tiempo de creación. os.path.getsize() devuelve la cantidad de datos en el archivo, representada en bytes.

$ python3 ospath_properties.py

File         : ospath_properties.py
Access time  : Fri Aug 26 16:38:05 2016
Modified time: Fri Aug 26 15:50:48 2016
Change time  : Fri Aug 26 15:50:49 2016
Size         : 481

Probando archivos

Cuando un programa encuentra un nombre de ruta, a menudo necesita saber si la ruta se refiere a un archivo, directorio o enlace simbólico y si existe os.path incluye funciones para probar todas estas condiciones.

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()

Todas las funciones de prueba devuelven valores booleanos.

$ 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

Ver también