简体   繁体   English

Python os.path.join 在 Windows

[英]Python os.path.join on Windows

I am trying to learn python and am making a program that will output a script.我正在尝试学习 python 并正在制作一个程序,该程序将 output 作为脚本。 I want to use os.path.join, but am pretty confused.我想使用 os.path.join,但我很困惑。 According to the docs if I say:根据文档,如果我说:

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

I get "C:sourcedir" .我得到"C:sourcedir" According to the docs, this is normal, right?根据文档,这是正常的,对吧?

But when I use the copytree command, Python will output it the desired way, for example:但是当我使用 copytree 命令时,Python 将 output 以所需的方式显示,例如:

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

Here is the error code I get:这是我得到的错误代码:

WindowsError: [Error 3] The system cannot find the path specified: 'C:src/*.*'

If I wrap the os.path.join with os.path.normpath I get the same error.如果我用os.path.normpath os.path.join会得到同样的错误。

If this os.path.join can't be used this way, then I am confused as to its purpose.如果这个os.path.join不能以这种方式使用,那么我对它的目的感到困惑。

According to the pages suggested by Stack Overflow, slashes should not be used in join—that is correct, I assume?根据 Stack Overflow 建议的页面,连接中不应使用斜线——我想这是正确的吧?

To be even more pedantic, the most python doc consistent answer would be:更迂腐,最符合 python 文档的答案是:

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

Since you also need os.sep for the posix root path:由于您还需要 os.sep 作为 posix 根路径:

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

Windows has a concept of current directory for each drive. Windows 对每个驱动器都有一个当前目录的概念。 Because of that, "c:sourcedir" means "sourcedir" inside the current C: directory, and you'll need to specify an absolute directory.因此, "c:sourcedir"表示当前 C: 目录中的“sourcedir”,您需要指定一个绝对目录。

Any of these should work and give the same result, but I don't have a Windows VM fired up at the moment to double check:其中任何一个都应该工作并给出相同的结果,但我目前没有启动 Windows VM 来仔细检查:

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

To be pedantic, it's probably not good to hardcode either / or \\ as the path separator.为了迂腐,将 / 或 \\ 硬编码为路径分隔符可能不好。 Maybe this would be best?也许这会是最好的?

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

or或者

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

The reason os.path.join('C:', 'src') is not working as you expect is because of something in the documentation that you linked to: os.path.join('C:', 'src')没有按预期工作的原因是因为您链接到的文档中的某些内容:

Note that on Windows, since there is a current directory for each drive, os.path.join("c:", "foo") represents a path relative to the current directory on drive C: (c:foo), not c:\\foo.请注意,在 Windows 上,由于每个驱动器都有一个当前目录,因此 os.path.join("c:", "foo") 表示相对于驱动器 C: (c:foo) 上的当前目录的路径,而不是 c :\\foo.

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

For a system-agnostic solution that works on both Windows and Linux, no matter what the input path, one could use os.path.join(os.sep, rootdir + os.sep, targetdir)对于适用于 Windows 和 Linux 的系统无关解决方案,无论输入路径是什么,都可以使用os.path.join(os.sep, rootdir + os.sep, targetdir)

On WIndows:在 Windows 上:

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

On Linux:在 Linux 上:

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

I'd say this is a (windows)python bug.我会说这是一个(windows)python 错误。

Why bug?为什么会出错?

I think this statement should be True我认为这个说法应该是True

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

But it is False on windows machines.但它在 Windows 机器上是False

to join a windows path, try要加入 Windows 路径,请尝试

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

basically, you will need to escape the slash基本上,你需要逃避斜线

You have a few possible approaches to treat path on Windows, from the most hardcoded ones (as using raw string literals or escaping backslashes) to the least ones.您有几种可能的方法来处理 Windows 上的路径,从最硬编码的方法(如使用原始字符串文字或转义反斜杠)到最少的方法。 Here follows a few examples that will work as expected.下面是一些可以按预期工作的示例。 Use what better fits your needs.使用更适合您的需求。

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

Consent with @georg-同意@georg-

I would say then why we need lame os.path.join - better to use str.join or unicode.join eg我会说为什么我们需要蹩脚的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))

answering to your comment : "the others '//' 'c:', 'c:\\\\' did not work (C:\\\\ created two backslashes, C:\\ didn't work at all)"回答您的评论: “其他 '//' 'c:', 'c:\\\\' 不起作用(C:\\\\ 创建了两个反斜杠,C:\\ 根本不起作用)”

On windows using os.path.join('c:', 'sourcedir') will automatically add two backslashes \\\\ in front of sourcedir .在使用os.path.join('c:', 'sourcedir') Windows 上os.path.join('c:', 'sourcedir')将自动在sourcedir前面添加两个反斜杠\\\\

To resolve the path, as python works on windows also with forward slashes -> '/' , simply add .replace('\\\\','/') with os.path.join as below:-要解析路径,因为 python 在 Windows 上也可以使用正斜杠 -> '/' ,只需添加.replace('\\\\','/')os.path.join如下:-

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

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

output : 'C:/temp'输出: 'C:/临时'

The proposed solutions are interesting and offer a good reference, however they are only partially satisfying.所提出的解决方案很有趣并且提供了很好的参考,但是它们只是部分令人满意。 It is ok to manually add the separator when you have a single specific case or you know the format of the input string, but there can be cases where you want to do it programmatically on generic inputs.当您有一个特定的案例或者您知道输入字符串的格式时,可以手动添加分隔符,但在某些情况下,您可能希望在通用输入上以编程方式添加分隔符。

With a bit of experimenting, I believe the criteria is that the path delimiter is not added if the first segment is a drive letter, meaning a single letter followed by a colon, no matter if it corresponds to a real unit.通过一些实验,我认为标准是如果第一个段是驱动器号,则不添加路径分隔符,这意味着单个字母后跟一个冒号,无论它是否对应于一个真实的单位。

For example:例如:

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

A convenient way to test for the criteria and apply a path correction can be to use os.path.splitdrive comparing the first returned element to the test value, like t+os.path.sep if os.path.splitdrive(t)[0]==t else t .测试标准并应用路径校正的一种便捷方法是使用os.path.splitdrive将第一个返回的元素与测试值进行比较,例如t+os.path.sep if os.path.splitdrive(t)[0]==t else t

Test:测试:

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

it can be probably be improved to be more robust for trailing spaces, and I have tested it only on windows, but I hope it gives an idea.它可能会得到改进,以使其对尾随空间更加健壮,我仅在 Windows 上对其进行了测试,但我希望它提供一个想法。 See also Os.path : can you explain this behavior?另见Os.path :你能解释一下这种行为吗? for interesting details on systems other then windows.有关 Windows 以外系统的有趣详细信息。

I got around this by using:我通过使用解决了这个问题:

os.sep.join(list('C:', 'sourcedir'))

join here is not from os.path.join() , but from ''.join() join不是来自os.path.join() ,而是来自''.join()

It can be useful in the following situation:它在以下情况下很有用:

import os

some_path = r'C:\some_folder\some_file.txt'
path_items = some_path.split(os.sep)
same_path = os.sep.join(path_items)

For simplicity's sake, a workaround:为了简单起见,解决方法是:

my_path = r'D:\test\test2\file.txt' # original path string
drive_letter = my_path.split(':')[0] # avoid os.path.join relative path bs
my_path_parts = os.path.normpath(my_path.split(':')[1]).split(os.sep)

# do some path cmponent modifications here if you want

if drive_letter: # if drive letter exists
    drive_letter += ':\\'

my_new_path = drive_letter + os.path.join(*my_path_parts)
my_new_path

In windows using os.paht.join("/", "Temp") will result in /Temp by default but as strange as it sounds, there is no problem in using that path as a full path equivalent to "C:/Temp" and it works for both saving files and opening files.在 windows 中,使用os.paht.join("/", "Temp")默认会生成 /Temp,但听起来很奇怪,将该路径用作等效于 "C:/Temp" 的完整路径没有问题" 它适用于保存文件和打开文件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM