Python os.path.relpath行为

2024-09-28 23:18:46 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个目录bar在一个目录foo中,文件foo_file.txt在目录foo中,文件bar_file.txt在目录bar;即

computer$ ls
foo/
computer$ ls foo/
bar/  foo_file.txt
computer$ ls foo/bar/
bar_file.txt

使用pythonos.path.relpath函数,我希望:

os.path.relpath('foo/bar/bar_file.txt', 'foo/foo_file.txt')

给我:

'bar/bar_file.txt'

然而,它实际上给了我:

'../bar/bar_file.txt'

这是为什么?有没有一个简单的方法来达到我想要的行为?

编辑:这是在带有Python2.7.3的Linux上


Tags: 文件path方法函数目录txt编辑foo
3条回答

os.path.relpath()假设其参数是目录。

>>> os.path.join(os.path.relpath(os.path.dirname('foo/bar/bar_file.txt'),
        os.path.dirname('foo/foo_file.txt')),
        os.path.basename('foo/bar/bar_file.txt'))
'bar/bar_file.txt'
os.path.relpath(arg1, arg2) 

将给出arg2在arg1目录中的相对路径。在您的情况下,为了从arg2到arg1,您需要cd up one directory(..),go the bar directory(bar),and the bar_file.txt。因此,相对路径是

../bar/bar_file.txt

relpath有意外行为。它将路径的所有元素视为一个目录。所以,在这条路上:

/path/to/a/file.txtfile.txt也被视为一个目录。

这意味着当您在两条路径上运行relpath

>>> from os.path import relpath
>>> relpath('/path/to/dest/file.txt', '/path/to/origin/file.txt')
'../../dest/file.txt'

这是不正确的。从目录源到目标的真正相对路径是'../dest/file.txt'

如果你试图创建符号链接,但最终它们的格式不正确,这会特别令人沮丧。

解决方案

要解决这个问题,我们必须首先找出路径是否指向一个文件,如果不是,我们可以像往常一样进行比较,否则我们需要从末尾删除文件名,只与目录进行比较,然后将文件添加回末尾。

注意,只有在系统上实际创建了这些文件时,这才有效,python必须访问文件系统才能找到节点类型。

import os

def realrelpath(origin, dest): 
    '''Get the relative path between two paths, accounting for filepaths'''

    # get the absolute paths so that strings can be compared
    origin = os.path.abspath(origin) 
    dest = os.path.abspath(dest) 

    # find out if the origin and destination are filepaths
    origin_isfile = os.path.isfile(origin)
    dest_isfile = os.path.isfile(dest)

    # if dealing with filepaths, 
    if origin_isfile or dest_isfile:
        # get the base filename
        filename = os.path.basename(origin) if origin_isfile else os.path.basename(dest)
        # in cases where we're dealing with a file, use only the directory name
        origin = os.path.dirname(origin) if origin_isfile else origin
        dest = os.path.dirname(dest) if dest_isfile else dest 
        # get the relative path between directories, then re-add the filename
        return os.path.join(os.path.relpath(dest, origin), filename)  
    else:
        # if not dealing with any filepaths, just run relpath as usual
        return os.path.relpath(dest, origin)   


要获取从目录源到目标的实际相对路径,请运行:

>>> relrealpath('/path/to/origin/file.txt', '/path/to/dest/file.txt')
'../dest/file.txt'

我颠倒了参数顺序,因为在我的大脑中,更合理的说法是,“我想知道从arg1到arg2的相对路径”,标准的relpath实现是向后的(可能是因为UNIX就是这样做的)。

这种访问文件系统的需要是relpath具有如此奇怪行为的真正原因。文件系统调用很昂贵,所以python让您知道您是在处理文件还是在处理目录,并且只在您提供的路径上执行字符串操作。

注意:可能有一种方法可以使realrelpath函数更有效率。例如,我不确定是否需要abspath调用,或者是否可以通过返回更多信息的syscall与os.path.isfile检查绑定。我欢迎改进。

相关问题 更多 >