使用os.path.join()构建绝对路径

71

我想在Python中构建一个绝对路径,同时不关心诸如路径分隔符之类的事情。

编辑0:例如,在文件系统根目录下有一个目录/etc/init.d(在w32上为C:\etc\init.d),我只想从元素etcinit.d(在w32上,我可能还需要磁盘ID,例如C:)构建此路径。

为了不必担心路径分隔符,显然最好使用os.path.join()这个工具。但是它似乎只会创建相对路径:

 print("MYPATH: %s" % (os.path.join('etc', 'init.d'),)
 MYPATH: etc/init.d

添加一个虚拟的第一个元素(例如'')并没有帮助到任何事情:

 print("MYPATH: %s" % (os.path.join('', 'etc', 'init.d'),)
 MYPATH: etc/init.d

让第一个元素变成绝对定位显然有所帮助,但这有点违背使用 os.path.join() 的初衷。

 print("MYPATH: %s" % (os.path.join('/etc', 'init.d'),)
 MYPATH: /etc/init.d

编辑1:使用os.path.abspath()仅会尝试将相对路径转换为绝对路径,例如在工作目录/home/foo中运行以下命令:

 print("MYPATH: %s" % (os.path.abspath(os.path.join('etc', 'init.d')),)
 MYPATH: /home/foo/etc/init.d

那么,什么是标准的跨平台路径“root”方式?

 root = ??? # <--
 print("MYPATH: %s" % (os.path.join(root, 'etc', 'init.d'),)
 MYPATH: /etc/init.d

编辑2: 问题的关键在于:由于/etc/init.d中的前导斜杠使该路径成为绝对路径,是否有一种以编程方式构建此前导斜杠的方法?(我不想做出前导斜杠表示绝对路径的假设)


1
我不确定我是否正确地理解了你的问题,但是你可以简单地使用 os.path.abspath('python.exe'),在我的Windows机器上返回 'C:\\Python27\\python.exe' - Brad
我已经更新了问题,希望能够澄清我的需求。 - umläute
1
顺便提一下,相关的近似问题:https://dev59.com/sGct5IYBdhLWcg3wgNnR - Christoph
这些答案都对我没用。我该如何将 root_dir="C:/Users/folder"filename="data/file1.txt" 连接起来以获得绝对路径?在非 Windows 系统中,只需使用 os.path.join(root_dir, filename) 即可轻松解决,但我在 Windows 中找不到解决方案。 - mikey
5个回答

96

使用os.sep作为根路径对我有用:

path.join(os.sep, 'python', 'bin')

Linux:/python/bin

Windows:\python\bin

在此基础上添加 path.abspath(),可以在 Windows 上获得驱动器卷标,并且仍然兼容 Linux:

path.abspath(path.join(os.sep, 'python', 'bin'))

Linux: /python/bin

Windows: C:\python\bin


3
在Linux和Windows上似乎能够工作,所以加一。但感觉不对。可能会在其他一些晦涩的系统上出现问题,但我想不到还有哪些系统。仍然感觉像Python应该给我们一个明确的方法来做到这一点。这取决于以路径分隔符开头的绝对路径。 - kratenko

4

我认为你可以使用os.path.normpath。以下是在Windows上的示例:

>>> os.path.normpath("/etc/init.d")
'\\etc\\init.d'

我不确定关于驱动器前缀该怎么做,但是我认为省略它意味着“继续使用当前所在的驱动器”,这可能是您想要的。也许更熟悉Windows的人可以澄清一下?


1
这就是正确的答案,让Python来解决你所在的平台。 - hobs
我同意这种观点,但是它使用了完全限定的路径而不是os.path.join()。虽然了解这一点很有用,但它并不足以成为一个解决方案。 - Nomen Nescio

2

所以我想到的解决方法是通过跟随给定文件到达其根目录来构建文件系统的根:

def getRoot(file=None):
  if file is None:
      file='.'
  me=os.path.abspath(file)
  drive,path=os.path.splitdrive(me)
  while 1:
    path,folder=os.path.split(path)
    if not folder:
       break
  return drive+path

 os.path.join(getRoot(), 'etc', 'init.d')

代码可能会更简单:drive, path = os.path.splitdrive(me) if not drive: return os.path.split(path)[0] else: return drive - Christoph
嗯,我相信我的解决方案不是最符合Python风格的方式;但是你的解决方案将返回/foo/bar/baz,如果文件评估为/foo/bar/baz(基本上是Ansuman答案中提到的问题)。 - umläute
该死,你是对的。被 SO 上另一个答案误导了 >.< - Christoph
1
我觉得这很有趣,但我有点困惑为什么它仍然是被接受的答案。 - Patrick Trentin

1

因此,您可以通过sys.platform检查正在运行的操作系统。

在Windows上

>>> sys.platform
'win32'

在Linux上
>>> sys.platform
'linux2'

然后
if sys.platform == 'win32':
    ROOT = os.path.splitdrive(os.path.abspath('.'))[0]
elif sys.platform == 'linux2':
    ROOT = os.sep

请注意,'linux2' 可能不包括所有 Linux 发行版。

不,我真的需要文件系统的根目录(无论Python模块位于何处)。如果我在“/home/me”中运行它,“os.path.abspath('foo')”将返回(例如)“/home/me/foo”,而我确实需要“/foo”(或“C:\foo”)。 - umläute
我已更新问题以澄清为什么 os.path.abspath() 似乎对我没有帮助。 - umläute
如果您想要一个不基于文件的 ROOT,并且在特定项目中所有文件都使用相同的 ROOT。那么您可以将 ROOT(一个字符串值)存储在配置文件中,或者您可以在所有文件中定义一个硬编码值的 ROOT。我已经在我的答案中添加了这个。 - Ansuman Bebarta
问题是:什么使/etc成为绝对路径?(显然是前缀/,但是否有编程方法来获取此后缀?) - umläute
嗯,这对于OSX和GNU/Hurd系统来说没有任何帮助;使用“跨平台”时,我的意思是“无需关心平台”,而不是“手动讨论每个平台”。 - umläute
显示剩余2条评论

-1
你可以尝试使用os.path.splitdrive来获取你的驱动器/文件系统的名称,然后将其与你的foo字符串连接起来。

http://docs.python.org/2/library/os.path.html#os.path.splitdrive

类似于(未经测试!)

(drive, tail) = os.path.splitdrive(os.getcwd())
os.path.join(drive, 'foo')

应该就能解决问题了。


1
无法在Linux上工作 - 驱动器被设置为'',与其连接不会给出根路径。 - mheyman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接