在Windows中查找相对路径
这个问题看起来应该很简单,但我还没能搞定。
我需要一个函数,它接收两个参数,每个参数都是一个文件路径,可以是相对路径也可以是绝对路径。这个函数的作用是返回第一个路径(目标路径)相对于第二个路径(起始路径)解析后的路径。解析后的路径可以是相对于当前目录的,也可以是绝对路径(我不在乎)。
这里有一个尝试实现的代码,还有几个文档测试,展示了一些示例用例(并且显示了它在哪些地方失败)。我的源码库里也有一个可运行的脚本,不过它可能会有所更改。这个可运行的脚本如果没有提供参数就会运行文档测试,如果提供了一两个参数,就会传给findpath函数。
def findpath(target, start=os.path.curdir):
r"""
Find a path from start to target where target is relative to start.
>>> orig_wd = os.getcwd()
>>> os.chdir('c:\\windows') # so we know what the working directory is
>>> findpath('d:\\')
'd:\\'
>>> findpath('d:\\', 'c:\\windows')
'd:\\'
>>> findpath('\\bar', 'd:\\')
'd:\\bar'
>>> findpath('\\bar', 'd:\\foo') # fails with '\\bar'
'd:\\bar'
>>> findpath('bar', 'd:\\foo')
'd:\\foo\\bar'
>>> findpath('bar\\baz', 'd:\\foo')
'd:\\foo\\bar\\baz'
>>> findpath('\\baz', 'd:\\foo\\bar') # fails with '\\baz'
'd:\\baz'
Since we're on the C drive, findpath may be allowed to return
relative paths for targets on the same drive. I use abspath to
confirm that the ultimate target is what we expect.
>>> os.path.abspath(findpath('\\bar'))
'c:\\bar'
>>> os.path.abspath(findpath('bar'))
'c:\\windows\\bar'
>>> findpath('..', 'd:\\foo\\bar')
'd:\\foo'
>>> findpath('..\\bar', 'd:\\foo')
'd:\\bar'
The parent of the root directory is the root directory.
>>> findpath('..', 'd:\\')
'd:\\'
restore the original working directory
>>> os.chdir(orig_wd)
"""
return os.path.normpath(os.path.join(start, target))
从文档测试中的注释可以看出,这个实现失败了,当起始路径指定了一个驱动器字母,而目标路径是相对于该驱动器根目录的。
这引出了几个问题:
- 这种行为是os.path.join的限制吗?换句话说,os.path.join('d:\foo', '\bar')应该解析为'd:\bar'吗?作为一个Windows用户,我倾向于认为是这样,但我不想相信像path.join这样成熟的函数需要修改才能处理这种用例。
- 有没有现成的目标路径解析器,比如findpath,可以在所有这些测试用例中都能正常工作?
- 如果对以上问题的回答是'不',那么你会如何实现这种期望的行为?
1 个回答
3
我同意你的看法:这看起来是os.path.join的一个不足之处。看起来你需要单独处理每个驱动器。这个代码能通过你所有的测试:
def findpath(target, start=os.path.curdir):
sdrive, start = os.path.splitdrive(start)
tdrive, target = os.path.splitdrive(target)
rdrive = tdrive or sdrive
return os.path.normpath(os.path.join(rdrive, os.path.join(start, target)))
(对了,我确实需要嵌套两个os.path.join才能让它工作……)