目的:文件名与路径的解析,构造,测试和其它工作。
使用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))
因为threefold
在three
后面没有路径分隔符,所以共有前缀是/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.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.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
参考
- os的标准库文档
- os.path的Python2到3的移植笔记
- pathlib —— 路径作为对象。
- os —— os.path的父模块。
- time —— time模块包括在os.path中的时间属性函数和易于读取的字符串之间进行转换的函数。