在Windows系统中,使用os.path.join时混用了反斜杠和正斜杠。

92

我倾向于只使用前斜杠路径('/'),Python在Windows上也可以使用。在os.path.join的描述中,它说这是正确的方式,如果你想要跨平台。但是当我使用它时,我得到了不同的斜杠:

import os

a = 'c:/'
b = 'myFirstDirectory/'
c = 'mySecondDirectory'
d = 'myThirdDirectory'
e = 'myExecutable.exe'


print os.path.join(a, b, c, d, e)

# Result:
c:/myFirstDirectory/mySecondDirectory\myThirdDirectory\myExecutable.exe

这是否正确?我应该检查和之后纠正它,还是有更好的方法?

谢谢

编辑: 在请求路径时我也会得到混合的斜杠

import sys
for item in sys.path:
    print item

# Result:
C:\Program Files\Autodesk\Maya2013.5\bin
C:\Program Files\Autodesk\Maya2013.5\mentalray\scripts\AETemplates
C:\Program Files\Autodesk\Maya2013.5\Python
C:\Program Files\Autodesk\Maya2013.5\Python\lib\site-packages
C:\Program Files\Autodesk\Maya2013.5\bin\python26.zip\lib-tk
C:/Users/nookie/Documents/maya/2013.5-x64/prefs/scripts
C:/Users/nookie/Documents/maya/2013.5-x64/scripts
C:/Users/nookie/Documents/maya/scripts
C:\Program Files\Nuke7.0v4\lib\site-packages
C:\Program Files\Nuke7.0v4/plugins/modules

os 很聪明,可以自动识别你的操作系统需要哪些斜杠。为了正确使用它,请不要在字符串 a、b、c、d 和 e 中添加斜杠 - os 会自动添加它们。 - ejrb
1
我明白了,但是如果我在请求路径时混用斜杠怎么办?(我已经在第一篇帖子中更新了一个例子) - nookie
10
你可以使用 os.path.normpath(mixed_slashes_path) 来规范化斜杠。哦,我猜你是在Maya内部执行这个操作;它的行为非常类似于UNIX系统,因此在添加路径时会包含斜杠。 - dash-tom-bang
9个回答

73

您可以在path.join()后使用.replace()来确保斜杠是正确的:

# .replace() all backslashes with forwardslashes
print os.path.join(a, b, c, d, e).replace("\\","/")

这将产生输出:

c:/myFirstDirectory/mySecondDirectory/myThirdDirectory/myExecutable.exe

正如@sharpcloud建议的那样,最好从输入字符串中删除斜杠,但这是另一种方法。


8
直接导入posixpath而不是os.path,然后使用posixpath.join(a, b, c, d, e)可以始终返回正斜杠,这种方式是否更好呢? - semicolon
@semicolon,posixpath和导入os.path是一样的吗?无论如何,在我的Windows机器上,posixpath.join()仍然返回混合斜杠。 - Maximus
甚至更好的做法是使用os.abspath()来规范化各种内容。也许在posixpath中有适合的东西? - dash-tom-bang
如果代码在类Unix系统上运行,这种方法会添加一个错误。换句话说,它会在你的代码中放置一个定时炸弹,由“代码被移植”触发 - 这正是你已经从代码深处遇到太多问题的情况。 - toolforger
我在wsl环境中工作,因此我需要在开头使用双反斜杠,然后是正斜杠。我执行 local_path = '\\\\' + path.join(home_w, repo).split('\\\\')[1].replace('\\', '/')。结果为:\\wsl$/debian/home../ - Timo
显示剩余6条评论

44

您现在需要自己提供一些斜杠,并让os.path.join挑选其余的。最好让Python选择全部或者全部自己提供。对于路径的后半部分,Python使用反斜杠,因为在Windows上反斜杠是默认的。

import os

a = 'c:' # removed slash
b = 'myFirstDirectory' # removed slash
c = 'mySecondDirectory'
d = 'myThirdDirectory'
e = 'myExecutable.exe'

print os.path.join(a + os.sep, b, c, d, e)

我没有测试过这个,但希望这可以帮到你。通常情况下,有一个基本路径,只需要连接另一个元素,大多数是文件。

顺便说一下:您可以使用os.sep在需要操作系统分隔符时获取最佳的分隔符。

编辑:如dash-tom-bang所述,显然对于Windows,您需要包括路径根目录的分隔符。否则,您将创建相对路径而不是绝对路径。


1
谢谢你的回答,但是如果我在一个字符串中得到了斜杠(当有两个或更多文件夹时),该怎么办?我已经更新了第一篇帖子,其中包含我从sys.path获取的一些路径。 - nookie
1
这取决于路径来自哪里。但大多数情况下,您应该已经以正确的格式拥有这些斜杠。也就是说,如果您通过Python获取路径。如果您有一些外部来源不受您控制,并且该来源提供正斜杠而不是反斜杠,则可能需要先修复它。 - pyrocumulus
那么我之后应该检查字符串并确保格式正确吗? - nookie
不,我会在将其放入“os.path.join”之前检查您的外部输入(您显然不能控制格式)。这样,您可以确保“os.path.join”不会根据可能错误的输入做出错误决策。 - pyrocumulus
1
将根目录拆分并重新连接不会产生正确的结果;需要指定 C: 的根目录。请参见 https://dev59.com/1nE95IYBdhLWcg3wKq2q. - dash-tom-bang
显示剩余6条评论

19

尝试使用abspath(使用Python 3)

import os

a = 'c:/'
b = 'myFirstDirectory/'
c = 'mySecondDirectory'
d = 'myThirdDirectory'
e = 'myExecutable.exe'


print(os.path.abspath(os.path.join(a, b, c, d, e)))

输出:

c:\myFirstDirectory\mySecondDirectory\myThirdDirectory\myExecutable.exe

Process finished with exit code 0

6
os.path.abspath()首先调用os.path.normpath()。你可以在这里实现相同的功能,只需调用os.path.normpath()即可。 - Martijn Pieters
问题仍然存在,因为Windows无法正确处理反斜杠,并认为它是转义字符。 - Timo

9

基于评论的编辑:path = os.path.normpath(path)

我的先前回答缺乏处理转义字符的能力,因此不应该使用

  • First, convert the path to an array of folders and file name.
  • Second, glue them back together using the correct symbol.

    import os   
    path = 'c:\www\app\my/folder/file.php'
    # split the path to parts by either slash symbol:
    path = re.compile(r"[\/]").split(path)
    # join the path using the correct slash symbol:
    path = os.path.join(*path)
    

3
请注意,如果您的字符串中恰好使用 \ 用于转义文件夹中的空格,则此方法将失效。例如,"/usr/my\ files" 将被翻译为 "usr","my"," files" 而不是 "usr","my files" - oriadam
10
不要重复造轮子,只需使用 os.path.normpath() - Martijn Pieters

8

如果出于任何原因,您需要自己提供路径,并且您正在使用 Python 3.4 及以上版本,则可以使用 pathlib

from pathlib import Path, PurePosixPath

a = PurePosixPath('c:/')
b = PurePosixPath('myFirstDirectory/')
c = 'mySecondDirectory'
d = 'myThirdDirectory'
e = 'myExecutable.exe'

print(a / b / c / d / e)

# Result
c:/myFirstDirectory/mySecondDirectory/myThirdDirectory/myExecutable.exe

当我需要用户提供资产目录的位置时,我的代码使用 Windows 路径字符串进行查找,因此我使用了这个方法。

In [1]: from pathlib import Path, PureWindowsPath
In [2]: USER_ASSETS_DIR = Path('/asset/dir') # user provides this form environment variable
In [3]: SPECIFIC_ASSET = PureWindowsPath('some\\asset')
In [4]: USER_ASSETS_DIR / SPECIFIC_ASSET

Out[4]: PosixPath('/asset/dir/some/asset')

2

os 会自动添加斜杠,并确保不重复添加,请在字符串中省略它们。

import os

# Don't add your own slashes
a = 'C:'
b = 'myFirstDirectory' 
c = 'mySecondDirectory'
d = 'myThirdDirectory'
e = 'myExecutable.exe'

print os.path.join(a, b, c, d, e)
C:\myFirstDirectory\mySecondDirectory\myThirdDirectory\myExecutable.exe

额外信息:

我不确定为什么您在系统路径中混合使用了斜杠(您是否使用Linux操作系统添加了一些文件夹?),但请尝试检查

print os.path.isdir(os.path.join('C:','Users','nookie'))

如果这是True,则os适用于您的混合斜杠。

无论如何,我建议避免将目录名称硬编码到程序中。 您的sys.path循环是提取这些目录的安全方式。 然后,您可以使用一些字符串方法或正则表达式来选择所需的文件夹。


os.path.isdir(os.path.join('C:','Users','nookie')) 返回 False。 我没有使用任何 Linux 操作系统来添加我的文件夹,这些文件夹只是从软件安装中获取的! - nookie
1
你使用的是哪个版本的Python,@ejrb?因为在我的版本中,我没有看到第一个斜杠。(我看到的是C:myFirstDirectory\mySecondDirectory... - dash-tom-bang

1

Postgres命令行客户端psql即使在Windows系统上也不接受反斜杠:

>psql -U user -h 111.111.111.111 -d mydb
psql (12.2, server 12.5 . . .
. . .
mydb=> \i C:\my\path\myscript.sql
C:: Permission denied

当从Python 3.8.6执行时需要修复它。不想采用简单的字符串替换,而是使用现有的函数:

script_path = Path(script_dir).resolve()
input_sql = f'\\i {script_path.joinpath("myscript.sql").as_posix()}\n'

但是在内部它有:
# ...\Programs\Python\Python38\Lib\pathlib.py
    def as_posix(self):
        """Return the string representation of the path with forward (/)
        slashes."""
        f = self._flavour
        return str(self).replace(f.sep, '/')

1

你也可以这样做:

import re

a = 'c:/'
b = 'myFirstDirectory/'
c = 'mySecondDirectory'
d = 'myThirdDirectory'
e = 'myExecutable.exe'

joined = os.path.join(a, b, c, d, e)
formatted = re.sub(r'/|\\', re.escape(os.sep), joined)

这将把您潜在的混合斜杠转换为符合操作系统要求的斜杠。
我知道这是一个古老的话题,但我忍不住。 :)

0
我处理这个问题的方式非常简单:无论路径数量和正确性如何,都使用rstrip函数去掉所有路径中的斜杠,然后使用正确的分隔符将这些路径重新连接起来。
import os

def join_path_regardless_of_separators(*paths):
    return os.path.sep.join(path.rstrip(r"\/") for path in paths)
 
a = 'c:/'
b = 'myFirstDirectory/'
c = 'mySecondDirectory'
d = 'myThirdDirectory\\\\\\/'
e = 'myExecutable.exe'
join_path_regardless_of_separators(a, b, c, d, e)
>>> 'c:\\myFirstDirectory\\mySecondDirectory\\myThirdDirectory\\myExecutable.exe'

另一种使用它的方式,可以得到相同的结果:

join_path_regardless_of_separators(*"""c:////\\\\
                                       myFirstDirectory/
                                       mySecondDirectory\\\\
                                       myThirdDirectory/////
                                       myExecutable.exe
                                    """.split())

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