Python os.path.join в Windows

99

Я пытаюсь изучить Python и делаю программу, которая выводит скрипт. Я хочу использовать os.path.join, но очень запутался. Согласно документам, если я скажу:

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.joinс os.path.normpathя получаю ту же ошибку.

Если это os.path.joinнельзя использовать таким образом, то я не понимаю его цель.

Согласно страницам, предложенным Stack Overflow, косые черты не должны использоваться в соединении - это правильно, я полагаю?

Фрэнк Э.
источник

Ответы:

60

В Windows есть концепция текущего каталога для каждого диска. По этой "c:sourcedir"причине это означает «sourcedir» внутри текущего каталога C :, и вам нужно указать абсолютный каталог.

Любой из них должен работать и давать тот же результат, но у меня нет виртуальной машины Windows, запущенной на данный момент для двойной проверки:

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

источник
8
os.path.join ('C: /', 'sourcedir') работал, как ожидалось. Большое спасибо, сэр :) другие '//' 'c:' 'c: \\' не работали (C: \\ создал две обратные косые черты, C: \ вообще не работал) Еще раз спасибо ghostdog74 , Smashery и Роджер Пэйт. Я у вас в долгу :)
Фрэнк Э.
Извините, разрывы строк не были оставлены в комментариях, это выглядит очень беспорядочно
Фрэнк Э.
Даже если в некоторых случаях это работает, ответ @AndreasT - гораздо лучшее решение. Использование os.sep будет выбирать между / и \ в зависимости от ОС.
SenhorLucas 05
Есть ли смысл использовать os.path.joinили os.sepвсе c:равно оговаривать ? c:не имеет смысла на других ОС.
naught101
все эти решения удовлетворяют только частично. Можно вручную добавить разделитель, когда у вас есть один конкретный случай, но если вы хотите сделать это программно, какие критерии os.path.join('c:','folder')работают иначе os.path.join('folder','file')? Это потому, :что 'c:' - это диск?
Vincenzooo
125

Чтобы быть еще более педантичным, наиболее последовательным ответом на Python будет следующий:

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

Так как вам также нужен os.sep для корневого пути posix:

mypath = os.path.join(os.sep, 'usr', 'lib')
Андреаст
источник
5
Простите за незнание - похоже, что код по-прежнему различается в Windows и Linux, так что же os.sepлучше?
pianoJames
3
Обратите внимание на этот сбой при инъекции os.sep. Он работает только после пустой буквы диска. >>> os.path.join ("C: \ goodbye", os.sep, "temp") 'C: \\ temp'
Jobu
1
@pianoJames, мой ответ основан на этом, чтобы предоставить системно-независимое решение: stackoverflow.com/a/51276165/3996580
Скотт Гиганте
Я не понимаю смысла всех этих «педантичных» решений. os.sepполезен, когда вы хотите управлять путями, не делая предположений о разделителе. Бессмысленно использовать с, os.path.join()так как он уже знает правильный разделитель. Это также бессмысленно, если вам нужно явно указать корневой каталог по имени (как вы можете видеть в своем собственном примере). Почему "c:" + os.sepвместо того, чтобы просто "c:\\", или os.sep + "usr"вместо того, чтобы просто "/usr"? Также обратите внимание, что в оболочках Win вы не cd c:можете cd c:\ , но можете , предполагая, что корневое имя на самом деле c:\ .
Майкл Экока,
13

Причина os.path.join('C:', 'src')не работает так, как вы ожидаете, из-за чего-то в документации, на которую вы ссылаетесь:

Обратите внимание, что в Windows, поскольку для каждого диска существует текущий каталог, os.path.join ("c:", "foo") представляет путь относительно текущего каталога на диске C: (c: foo), а не c : \ foo.

Как сказал призрак, вы, вероятно, захотите mypath=os.path.join('c:\\', 'sourcedir')

Smashery
источник
12

Чтобы быть педантичным, вероятно, не стоит жестко указывать / или \ в качестве разделителя пути. Может, так будет лучше?

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

или

mypath = os.path.join('c:' + os.sep, 'sourcedir')
Мэтт Болл
источник
12

Для независимого от системы решения, которое работает как в 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'
Скотт Гиганте
источник
1
Благодарность! Это даже более полезно, поскольку не страдает от ошибки, о которой упоминал ранее @Jobu: os.path.join (os.sep, "C: \\ a" + os.sep, "b") возвращает "C: \\ a \\ b "в Windows.
pianoJames
1
Каким образом любой из этих примеров является системным агностиком? c:не существует в * nix и usrне существует в Windows ..
naught101
Вызов функции не 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 вы не можете просто сделать cd c:, вы бы необходимо указать обратную косую черту в конце), так зачем же делать вид, что это не так?
Майкл Экока
7

Я бы сказал, что это ошибка Python (Windows).

Почему глючит?

Я думаю это заявление должно быть True

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

Но это Falseна машинах Windows.

Георг
источник
1
Я склонен согласиться с тем, что это ошибка Python. Так ли это до сих пор? ( Написано из славного утопического будущего конца 2015 года. )
Сесил Карри,
Я не могу ответить на этот вопрос в отношении окон, поскольку у меня нет доступа к машине с Windows, но я предполагаю, что поведение python в отношении этого вопроса не изменилось. В любом случае, этот оператор также неверен для реализаций Linux, поскольку первый оператор возвращает путь без ведущего разделителя (он же корневой каталог), тогда как второй оператор возвращает путь, включая ведущий разделитель.
georg 06
Так что мне больше не нравится мой ответ на этот вопрос. Но мне также не нравится поведение питона по этому поводу.
georg 06
@Cecil Я сейчас задаю этот вопрос из-за той же проблемы ... похоже, что все еще так.
joshmcode
5

чтобы присоединиться к пути Windows, попробуйте

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

в основном вам нужно избегать косой черты

призрачная собака74
источник
4

У вас есть несколько возможных подходов к обработке пути в 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
Марко Гомес
источник
0

Согласие с @ georg-

Тогда я бы сказал, зачем нам хромой os.path.join- лучше использовать str.joinили unicode.joinнапример

sys.path.append('{0}'.join(os.path.dirname(__file__).split(os.path.sep)[0:-1]).format(os.path.sep))
SIslam
источник
2
да, да, так стало понятнее. Почему бы не использовать регулярные выражения, пока вы это делаете? или вызвать Perl-скрипт и обработать вывод?
Жан-Франсуа Фабр
Я не думаю, что это хорошая идея, потому что os.path.join - довольно хорошая семантика ... Так что вы видите это в коде и сразу понимаете, что происходит.
SenhorLucas
0

отвечая на ваш комментарий: "другие '//' 'c:', 'c: \\' не работали (C: \\ создал две обратные косые черты, C: \ вообще не работал)"

В Windows при использовании os.path.join('c:', 'sourcedir') автоматически добавляются две обратные косые черты \\перед sourcedir .

Для того, чтобы определить путь, так как питон работает на окнах и с косой чертой -> «/» , просто добавьте .replace('\\','/')с , os.path.joinкак показано ниже: -

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

например: os.path.join('c:\\', 'temp').replace('\\','/')

вывод: 'C: / temp'

Пратул
источник
0

Предлагаемые решения интересны и служат хорошим ориентиром, однако удовлетворяют лишь частично. Можно вручную добавить разделитель, если у вас есть один конкретный случай или вы знаете формат входной строки, но могут быть случаи, когда вы хотите сделать это программно для общих входов.

Немного поэкспериментировав, я считаю, что критерием является то, что разделитель пути не добавляется, если первый сегмент является буквой диска, то есть одной буквой, за которой следует двоеточие, независимо от того, соответствует ли она реальной единице.

Например:

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: вы можете объяснить такое поведение? для получения интересных подробностей о других системах, кроме Windows.

Винчензуоо
источник