【问题标题】:Python os.path.join on WindowsWindows 上的 Python os.path.join
【发布时间】:2011-01-26 05:44:38
【问题描述】:

我正在尝试学习 python 并正在制作一个可以输出脚本的程序。我想使用 os.path.join,但我很困惑。根据docs,如果我说:

os.path.join('c:', 'sourcedir')

我收到"C:sourcedir"。根据文档,这是正常的,对吧?

但是当我使用copytree命令时,Python会以想要的方式输出,例如:

import shutil
src = os.path.join('c:', 'src')
dst = os.path.join('c:', 'dst')
shutil.copytree(src, dst)

这是我得到的错误代码:

WindowsError: [错误 3] 系统找不到指定的路径:'C:src/*.*'

如果我用os.path.normpath 包装os.path.join,我会得到同样的错误。

如果这个os.path.join不能这样使用,那么我对它的用途感到困惑。

根据 Stack Overflow 建议的页面,在连接中不应该使用斜杠——我认为这是正确的?

【问题讨论】:

    标签: python windows path-manipulation


    【解决方案1】:

    加入windows路径,试试

    mypath=os.path.join('c:\\', 'sourcedir')
    

    基本上,你需要转义斜线

    【讨论】:

      【解决方案2】:

      os.path.join('C:', 'src') 未按预期工作的原因是由于您链接到的文档中的某些内容:

      请注意,在 Windows 上,由于存在 每个驱动器的当前目录, os.path.join("c:", "foo") 代表一个 相对于当前目录的路径 在驱动器 C: (c:foo) 上,而不是 c:\foo。

      正如ghostdog所说,你可能想要mypath=os.path.join('c:\\', 'sourcedir')

      【讨论】:

        【解决方案3】:

        Windows 对每个驱动器都有一个当前目录的概念。因此,"c:sourcedir" 表示当前 C: 目录中的“sourcedir”,您需要指定一个绝对目录。

        其中任何一个都应该工作并给出相同的结果,但我目前没有启动 Windows VM 来仔细检查:

        "c:/sourcedir"
        os.path.join("/", "c:", "sourcedir")
        os.path.join("c:/", "sourcedir")
        

        【讨论】:

        • os.path.join('C:/', 'sourcedir') 按预期工作。非常感谢您,先生 :) 其他人 '//' 'c:' 'c:\\' 不起作用(C:\\ 创建了两个反斜杠,C:\ 根本不起作用)再次感谢 ghostdog74 、 Smashery 和罗杰佩特。我欠你的债:)
        • 抱歉,评论中没有保留换行符,看起来很乱
        • 即使这在某些情况下有效,@AndreasT 的答案也是一个更好的解决方案。使用 os.sep 将根据操作系统在 / 和 \ 之间进行选择。
        • 如果您要指定c:,使用os.path.joinos.sep 有什么意义吗? c: 在其他操作系统上毫无意义。
        • 所有这些解决方案只是部分令人满意。当您有单个特定情况时,可以手动添加分隔符,但如果您想以编程方式执行此操作,os.path.join('c:','folder')os.path.join('folder','file') 的工作方式不同的标准是什么?是因为: 还是因为'c:` 是一个驱动器?
        【解决方案4】:

        为了迂腐,硬编码 / 或 \ 作为路径分隔符可能不太好。也许这样最好?

        mypath = os.path.join('c:%s' % os.sep, 'sourcedir')
        

        mypath = os.path.join('c:' + os.sep, 'sourcedir')
        

        【讨论】:

          【解决方案5】:

          为了更加迂腐,最一致的 python doc 答案是:

          mypath = os.path.join('c:', os.sep, 'sourcedir')
          

          因为您还需要 os.sep 作为 posix 根路径:

          mypath = os.path.join(os.sep, 'usr', 'lib')
          

          【讨论】:

          • 原谅我的无知 - 看起来代码在 Windows 和 Linux 之间仍然存在差异,那么是什么让 os.sep 更胜一筹?
          • 在尝试注入 os.sep 时请注意这个问题。它仅在裸驱动器号之后起作用。 >>> os.path.join("C:\goodbye", os.sep, "temp") 'C:\\temp'
          • @pianoJames 我的答案建立在这个基础之上,以提供与系统无关的解决方案:stackoverflow.com/a/51276165/3996580
          • 我不明白所有这些“迂腐”解决方案的意义。 os.sep 在您想要操纵路径而不对分隔符进行假设时很有用。与os.path.join() 一起使用毫无意义,因为它已经知道正确的分隔符。如果您最终需要按名称显式指定根目录(如您在自己的示例中所见),这也是没有意义的。为什么用"c:" + os.sep 而不是简单的"c:\\",或者os.sep + "usr" 而不是简单的"/usr"?另请注意,在 Win shell 中您不能cd c: 但可以cd c:\ ,这表明根名称实际上是c:\
          【解决方案6】:

          我会说这是一个 (windows)python 错误。

          为什么会出错?

          我觉得这个说法应该是True

          os.path.join(*os.path.dirname(os.path.abspath(__file__)).split(os.path.sep))==os.path.dirname(os.path.abspath(__file__))
          

          但在 Windows 机器上是False

          【讨论】:

          • 我倾向于同意这构成了一个 Python 错误。还是这样吗? (写于 2015 年末美好的乌托邦未来。
          • 我无法回答关于 windows 的这个问题,因为我无法访问 windows 机器,但我猜 python 在这个问题上的行为没有改变。无论如何,这个语句对于 Linux 实现也不是真的,因为第一个语句返回没有前导分隔符的路径(也就是根目录),而第二个语句返回包含前导分隔符的路径。
          • 所以我实际上不再喜欢我对这个问题的回答了。但我也不喜欢 python 在这方面的行为。
          • @Cecil 我现在就这个问题是因为同样的问题......它似乎仍然是这种情况。
          【解决方案7】:

          同意@georg-

          那我会说为什么我们需要蹩脚的os.path.join- 最好使用str.joinunicode.join,例如

          sys.path.append('{0}'.join(os.path.dirname(__file__).split(os.path.sep)[0:-1]).format(os.path.sep))
          

          【讨论】:

          • 是的,没错,这样更清楚。为什么不使用正则表达式呢?还是调用 perl 脚本并处理输出?
          • 我认为这不是一个好主意,因为 os.path.join 的语义非常好......所以你可以在代码中看到它并立即理解发生了什么。
          【解决方案8】:

          您有几种可能的方法来处理 Windows 上的路径,从最硬编码的方法(如使用原始字符串文字或转义反斜杠)到最少的方法。下面是一些可以按预期工作的示例。使用更适合您需求的。

          In[1]: from os.path import join, isdir
          
          In[2]: from os import sep
          
          In[3]: isdir(join("c:", "\\", "Users"))
          Out[3]: True
          
          In[4]: isdir(join("c:", "/", "Users"))
          Out[4]: True
          
          In[5]: isdir(join("c:", sep, "Users"))
          Out[5]: True
          

          【讨论】:

            【解决方案9】:

            对于一种适用于 Windows 和 Linux 的与系统无关的解决方案,无论输入路径是什么,都可以使用 os.path.join(os.sep, rootdir + os.sep, targetdir)

            在 Windows 上:

            >>> os.path.join(os.sep, "C:" + os.sep, "Windows")
            'C:\\Windows'
            

            在 Linux 上:

            >>> os.path.join(os.sep, "usr" + os.sep, "lib")
            '/usr/lib'
            

            【讨论】:

            • 谢谢!这甚至更有用,因为它不受@Jobu 前面提到的问题的影响: os.path.join(os.sep, "C:\\a" + os.sep, "b") 返回 "C: \\a\\b" 在 Windows 上。
            • 这些示例中的任何一个如何与系统无关? c: 在 *nix 上不存在,usr 在 Windows 上不存在..
            • 函数调用 os.path.join(os.sep, rootdir + os.sep, targetdir) 与系统无关正是因为它适用于这两个特定于系统的示例,无需更改代码。
            • 这个解决方案,就像启发它的早期帖子一样,仍然依赖于设置 rootdir,如 rootdir = "usr" if nix else "c:"。但是更直接和准确的rootdir = "/usr" if nix else "c:\\" 也同样有效,没有os.sep 杂技和随之而来的挠头。 *nix 上的根目录不会以正斜杠以外的任何内容开头,或者 Windows 的根目录名称不带尾随冒号和反斜杠(例如,在 Win shell 中,您不能只使用cd c:,您需要指定尾部反斜杠),那么为什么要假装不这样呢?
            【解决方案10】:

            回答您的评论:“其他 '//' 'c:', 'c:\\' 不起作用(C:\\ 创建了两个反斜杠,C:\ 根本不起作用)"

            在 Windows 上使用 os.path.join('c:', 'sourcedir') 会自动在sourcedir前面添加两个反斜杠\\

            要解析路径,因为 python 在 windows 上也可以使用正斜杠 -> '/',只需添加 .replace('\\','/')os.path.join 如下:-

            os.path.join('c:\\', 'sourcedir').replace('\\','/')

            例如:os.path.join('c:\\', 'temp').replace('\\','/')

            输出:'C:/temp'

            【讨论】:

              【解决方案11】:

              提出的解决方案很有趣,并提供了很好的参考,但它们只是部分令人满意。当您有单个特定情况或您知道输入字符串的格式时,可以手动添加分隔符,但在某些情况下,您可能希望在通用输入上以编程方式执行此操作。

              通过一些实验,我认为标准是如果第一段是驱动器号,则不添加路径分隔符,这意味着单个字母后跟冒号,无论它是否对应于实际单元。

              例如:

              import os
              testval = ['c:','c:\\','d:','j:','jr:','data:']
              
              for t in testval:
                  print ('test value: ',t,', join to "folder"',os.path.join(t,'folder'))
              
              test value:  c: , join to "folder" c:folder
              test value:  c:\ , join to "folder" c:\folder
              test value:  d: , join to "folder" d:folder
              test value:  j: , join to "folder" j:folder
              test value:  jr: , join to "folder" jr:\folder
              test value:  data: , join to "folder" data:\folder
              

              测试标准和应用路径校正的便捷方法是使用os.path.splitdrive 将第一个返回的元素与测试值进行比较,例如t+os.path.sep if os.path.splitdrive(t)[0]==t else t

              测试:

              for t in testval:
                  corrected = t+os.path.sep if os.path.splitdrive(t)[0]==t else t
                  print ('original: %s\tcorrected: %s'%(t,corrected),' join corrected->',os.path.join(corrected,'folder'))
              
              original: c:    corrected: c:\  join corrected-> c:\folder
              original: c:\   corrected: c:\  join corrected-> c:\folder
              original: d:    corrected: d:\  join corrected-> d:\folder
              original: j:    corrected: j:\  join corrected-> j:\folder
              original: jr:   corrected: jr:  join corrected-> jr:\folder
              original: data: corrected: data:  join corrected-> data:\folder
              

              它可能会被改进为更健壮的尾随空格,我只在 Windows 上测试过它,但我希望它能给你一个想法。 另请参阅Os.path : can you explain this behavior?,了解有关除 windows 之外的系统的有趣详细信息。

              【讨论】:

                猜你喜欢
                • 2021-08-18
                • 2011-12-13
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-01-27
                • 1970-01-01
                • 2011-06-26
                • 2018-06-10
                相关资源
                最近更新 更多