我们可以利用os.path模块提供的函数更容易地在跨平台上处理文件. 即使我们的程序不是用于夸平台, 也应该使用os.path来让路径名字更加可靠.
os.path中的第一个函数集可以用于解析文件名字符串为不同部分. 要注意到这些函数的解析不依赖于被解析的路径是否真正存在, 他们只处理字符串.
路径解析依赖于一些os实现定义好的变量, 如:
split() 函数将路径切分成两个两部分并返回一个元组, 它的第二个元素是路径的最后一部份, 第一个元素是路径的前面部分.
import os.path
for path in [ '/one/two/three','/one/two/three/','/',',']:
print '"%s" : "%s"' % (path, os.path.split(path))
$ python ospath_split.py
"/one/two/three" : "('/one/two', 'three')"
"/one/two/three/" : "('/one/two/three', '')"
"/" : "('/', '')"
"." : "('', '.')"
"" : "('', '')"
basename() 返回的值和 split() 返回的第二个值相同.
import os.path
for path in [ '/one/two/three','/one/two/three/','/','.','']:
print '"%s" : "%s"' % (path, os.path.basename(path))
$ python ospath_basename.py
"/one/two/three" : "three"
"/one/two/three/" : ""
"/" : ""
"." : "."
"" : ""
dirname() 返回的值是和 split() 返回的第一个值相同.
import os.path
for path in [ '/one/two/three', '/one/two/three/','/','.','']:
print '"%s" : "%s"' % (path, os.path.dirname(path))
$ python ospath_dirname.py
"/one/two/three" : "/one/two"
"/one/two/three/" : "/one/two/three"
"/" : "/"
"." : ""
"" : ""
splitext() 和 split() 类似但是分隔路径的扩展名, 而不是目录名.
import os.path
for path in [ 'filename.txt', 'filename', '/path/to/filename.txt', '/', '' ]:
print '"%s" :' % path, os.path.splitext(path)
$ python ospath_splitext.py
"filename.txt" : ('filename', '.txt')
"filename" : ('filename', '')
"/path/to/filename.txt" : ('/path/to/filename', '.txt')
"/" : ('/', '')
"" : ('', '')
commonprefix() 取一个路径列表作为参数, 返回一个单一的字符串表示这些路径公共的前缀. 这个值可能是一个实际上不存在的路径. 路径分割符是被忽略的, 所以前缀可能在在分割处被截断.
import os.path
paths = ['/one/two/three/four','/one/two/threefold','/one/two/three/',]
print paths
print os.path.commonprefix(paths)
$ python ospath_commonprefix.py
['/one/two/three/four', '/one/two/threefold', '/one/two/three/']
/one/two/three
除了将现有的路径分隔外, 你可能经常会将多个字符串组合成一个路径.
可以使用 join() 将多个路径部分组合成一个单个值:
import os.path
for parts in [ ('one', 'two', 'three'),('/', 'one', 'two', 'three'),('/one', '/two', '/three'),]:
print parts, ':', os.path.join(*parts)
$ python ospath_join.py
('one', 'two', 'three') : one/two/three
('/', 'one', 'two', 'three') : /one/two/three
('/one', '/two', '/three') : /three
如果路径中包含变量部分, 也能自动将她扩展出来. 例如, expanduser() 可以将波浪线(~)扩展成用户的主目录.
import os.path
for user in [ '', 'dhellmann', 'postgres' ]:
lookup = '~' + user
print lookup, ':', os.path.expanduser(lookup)
$ python ospath_expanduser.py
~ : /Users/dhellmann
~dhellmann : /Users/dhellmann
~postgres : /var/empty
expandvars() 是能更一般的扩展出现在路径中的环境变量.
import os.path
import os
os.environ['MYVAR'] = 'VALUE'
print os.path.expandvars('/path/to/$MYVAR')
$ python ospath_expandvars.py
/path/to/VALUE
使用 join() 组装成的, 或嵌入了变量的Paths路径可能会以多余的分隔符结束或含有相对路径部份. 使用 normpath() 将这些清除:
import os.path
for path in [ 'one//two//three', 'one/./two/./three', 'one/../one/two/three',]:
print path, ':', os.path.normpath(path)
$ python ospath_normpath.py
one//two//three : one/two/three
one/./two/./three : one/two/three
one/../one/two/three : one/two/three
使用 abspath() 将一个相对路径转换成绝对路径.
import os.path
for path in [ '.', '..', './one/two/three', '../one/two/three']:
print '"%s" : "%s"' % (path, os.path.abspath(path))
$ python ospath_abspath.py
"." : "/Users/dhellmann/Documents/PyMOTW/in_progress/ospath"
".." : "/Users/dhellmann/Documents/PyMOTW/in_progress"
"./one/two/three" : "/Users/dhellmann/Documents/PyMOTW/in_progress/ospath/one/two/three"
"../one/two/three" : "/Users/dhellmann/Documents/PyMOTW/in_progress/one/two/three"
除了处理路径外, os.path 还可以包含一些用于检索文件属性的函数, 他们比 os.stat() 更方便:
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__)
$ python ospath_properties.py
File : /Users/dhellmann/Documents/PyMOTW/in_progress/ospath/ospath_properties.py
Access time : Sun Jan 27 15:40:20 2008
Modified time: Sun Jan 27 15:39:06 2008
Change time : Sun Jan 27 15:39:06 2008
Size : 478
当你的程序含一个路径名时, 他通常需要知道这个路径是否是文件还是目录. 如果你的平台支持它, 你需要知道这个路径是指向一个符号链接还是是一个挂载点. 你也可能想测试路径是否存在. os.path 提供测试这些条件的函数.
import os.path
for file in [ __file__, os.path.dirname(__file__), '/', './broken_link']:
print 'File :', 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
$ python ospath_tests.py
File : /Users/dhellmann/Documents/PyMOTW/in_progress/ospath/ospath_tests.py
Absolute : True
Is File? : True
Is Dir? : False
Is Link? : False
Mountpoint? : False
Exists? : True
Link Exists?: True
File : /Users/dhellmann/Documents/PyMOTW/in_progress/ospath
Absolute : True
Is File? : False
Is Dir? : True
Is Link? : False
Mountpoint? : False
Exists? : True
Link Exists?: True
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.walk() 遍历树中的所有目录, 并调用一个你提供的函数, 同时将目录名和目录中包含内容的名字传递给这个函数. 下面的例子将递归的列出目录, 但忽略.svn目录.
import os.path
import pprint
def visit(arg, dirname, names):
print dirname, arg
for name in names:
subname = os.path.join(dirname, name)
if os.path.isdir(subname):
print ' %s/' % name
else:
print ' %s' % name
# Do not recurse into .svn directory
if '.svn' in names:
names.remove('.svn')
print
os.path.walk('..', visit, '(User data)')
$ python ospath_walk.py
.. (User data)
.svn/
ospath/
../ospath (User data)
.svn/
__init__.py
ospath_abspath.py
ospath_basename.py
ospath_commonprefix.py
ospath_dirname.py
ospath_expanduser.py
ospath_expandvars.py
ospath_join.py
ospath_normpath.py
ospath_properties.py
ospath_split.py
ospath_splitext.py
ospath_tests.py
ospath_walk.py