【问题标题】:Python os.path.relpath behaviorPython os.path.relpath 行为
【发布时间】:2013-07-04 14:23:43
【问题描述】:

我在目录foo 中有一个目录bar,文件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

使用 python os.path.relpath 函数,我期望:

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

给我:

'bar/bar_file.txt'

然而,它实际上给了我:

'../bar/bar_file.txt'

这是为什么?有没有简单的方法来获得我想要的行为?

编辑:这是在带有 Python 2.7.3 的 Linux 上

【问题讨论】:

  • 我意识到我可以使用os.path.relpath('foo/bar/bar_file.txt', os.path.dirname('foo/foo_file.txt')) 来获得我想要的结果。仍然好奇为什么原始代码不起作用。

标签: python path os.path


【解决方案1】:

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'

【讨论】:

【解决方案2】:
os.path.relpath(arg1, arg2) 

将给出 arg2 从 arg1 目录的相对路径。为了在您的情况下从 arg2 到 arg1,您需要 cd 一个目录(..),进入 bar 目录(bar),然后是 bar_file.txt。因此,相对路径为

../bar/bar_file.txt

【讨论】:

  • os.path.relpath(arg1, arg2) 将从 arg2 的目录中给出 arg1 的相对路径
【解决方案3】:

relpath 出现意外行为。它将路径的所有元素视为目录。所以,在路径中:

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

这意味着当你在两条路径上运行 relpath 时,比如说,

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

这是不正确的。从目录 origin 到 dest 的真正相对路径是'../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 调用是否是必要的,或者它们是否可以与os.path.isfile 检查捆绑在一起,并带有返回更多信息的系统调用。我欢迎改进。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-25
    • 2011-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多