os.path——文件名的平台无关操作

原文地址:https://pymotw.com/3/os.path/index.html

目的:文件名与路径的解析,构造,测试和其它工作。

使用os.path模块中的函数在多个平台上操作文件很容易。即使不想在平台之间移植的程序也应该使用os.path进行可靠的文件名解析。

1、解析路径

os.path模块中的第一组函数用于将表示文件名的字符串解析为它们的组成部分。重要的是要意识到,这些函数不依赖于实际存在的路径;它们仅仅是在字符串上操作。

路径解析依赖于在os模块中定义的几个变量:

  • os.sep——路径组成部分之间的分隔符(比如“/”或“\”)。
  • os.extsep——文件名和文件扩展名之间的分隔符(比如“.”)。
  • os.pardir——路径组成部分,表示遍历到目录树的上一层(比如“..”)。
  • os.curdir——路径组成部分,指向当前目录(比如“.”)。

split()函数把路径分割为两个部分,并返回包括结果的一个元组。元组的第二个元素是路径的最后一个组成部分,第一个元素是它之前的所有部分。

# 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()类似,但它根据扩展名分割,而不是目录分隔符划分路径。

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

在这里示例中,尽管有一个路径不包括three目录,但共有前缀字符串是/one/two/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))

因为threefoldthree后面没有路径分隔符,所以共有前缀是/one/two

$ python3 ospath_commonpath.py

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

PREFIX: /one/two

2、构建路径

除了将现有路径分割,还经常需要从字符串构建路径。使用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()更通用,可以扩展路径中出现的任何shell环境变量。

# 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

3、规范路径

使用jion()或者嵌入变量,从独立的字符串组合路径可能会带来额外的分隔符或相对路径组件。使用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.curdiros.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.path
import os

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'

4、文件时间

除了使用路径,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  : 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

5、测试文件

当程序遇到路径名时,通常需要知道路径指向文件,目录还是符号链接,以及它是否存在。os.path包括测试这些所有条件的函数。

# ospath_test.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

参考

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值