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"หมายถึง "ที่มา" ภายในไดเร็กทอรี C: ปัจจุบันและคุณจะต้องระบุไดเร็กทอรีสัมบูรณ์

สิ่งเหล่านี้ควรใช้งานได้และให้ผลลัพธ์เหมือนกัน แต่ฉันไม่มี Windows VM ที่ทำงานในขณะนี้เพื่อตรวจสอบอีกครั้ง:

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

8
os.path.join ('C: /', 'sourcedir') ทำงานตามที่คาดไว้ ฉันขอบคุณที่ดีมาก :) คนอื่น ๆ '//' c: '' c: \\ 'ไม่ทำงาน (C: \\ สร้างแบ็กสแลชสองตัว C: \ ไม่ทำงานเลย) ขอบคุณอีกครั้ง ghostdog74 , Smashery และ Roger Pate ฉันเป็นหนี้ของคุณ :)
Frank E.

ขออภัยไม่มีการแบ่งบรรทัดไว้ในความคิดเห็นมันดูยุ่งมาก
Frank E.

แม้ว่าจะใช้งานได้ในบางกรณีคำตอบของ @AndreasT เป็นทางออกที่ดีกว่า การใช้ os.sep จะเลือกระหว่าง / และ \ ขึ้นอยู่กับ OS
SenhorLucas

มีจุดใดในการใช้os.path.joinหรือos.sepถ้าคุณจะระบุc:ต่อไป? c:ไม่มีเหตุผลใน OS อื่น ๆ
naught101

โซลูชันทั้งหมดนี้เป็นที่น่าพอใจเพียงบางส่วนเท่านั้น คุณสามารถเพิ่มตัวคั่นด้วยตนเองได้เมื่อคุณมีกรณีเฉพาะเพียงกรณีเดียว แต่ในกรณีที่คุณต้องการทำแบบเป็นโปรแกรมเกณฑ์ที่ใช้os.path.join('c:','folder')งานแตกต่างจากos.path.join('folder','file')อะไร? เป็นเพราะ:หรือเพราะ 'c: `เป็นไดรฟ์?
Vincenzooo

125

คำตอบที่สอดคล้องกับ python doc มากที่สุดคือ:

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
โปรดทราบ snafu os.sepนี้เมื่อพยายามที่จะฉีด ใช้งานได้หลังจากอักษรระบุไดรฟ์เปล่าเท่านั้น >>> os.path.join ("C: \ goodbye", os.sep "temp") 'C: \\ temp'
Jobu

1
@pianoJames คำตอบของฉันสร้างขึ้นจากคำตอบนี้เพื่อให้เป็นโซลูชันที่ไม่เชื่อเรื่องพระเจ้า: stackoverflow.com/a/51276165/3996580
Scott Gigante

ฉันไม่เข้าใจประเด็นของวิธีแก้ปัญหาแบบ "อวดรู้" ทั้งหมดนี้ os.sepมีประโยชน์เมื่อคุณต้องการจัดการเส้นทางโดยไม่ต้องตั้งสมมติฐานเกี่ยวกับตัวคั่น มันไม่มีประโยชน์ที่จะใช้os.path.join()เนื่องจากมันรู้ตัวคั่นที่ถูกต้องแล้ว นอกจากนี้ยังไม่มีจุดหมายหากคุณจำเป็นต้องระบุไดเร็กทอรีรูทอย่างชัดเจนตามชื่อ (ดังที่คุณเห็นในตัวอย่างของคุณเอง) ทำไม"c:" + os.sepแทนที่จะเป็นเพียงแค่"c:\\"หรือos.sep + "usr"แทนที่จะเป็นเพียงแค่"/usr"? นอกจากนี้ยังทราบว่าในเปลือกหอยชนะคุณไม่สามารถcd c:แต่คุณสามารถบอกว่าชื่อรากที่เป็นจริงcd c:\ c:\
Michael Ekoka

13

สาเหตุที่os.path.join('C:', 'src')ไม่ได้ผลตามที่คุณคาดหวังเป็นเพราะบางสิ่งในเอกสารที่คุณเชื่อมโยงไป:

โปรดสังเกตว่าบน Windows เนื่องจากมีไดเร็กทอรีปัจจุบันสำหรับแต่ละไดรฟ์ os.path.join ("c:", "foo") จึงแสดงเส้นทางที่สัมพันธ์กับไดเร็กทอรีปัจจุบันบนไดรฟ์ C: (c: foo) ไม่ใช่ c : \ foo.

ตามที่โกสต์ด็อกกล่าวไว้คุณอาจต้องการ mypath=os.path.join('c:\\', 'sourcedir')


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
ขอบคุณ! สิ่งนี้มีประโยชน์มากยิ่งขึ้นเนื่องจากไม่ได้รับผลกระทบจาก gotcha ที่ @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)ไม่เชื่อเรื่องพระเจ้าอย่างแม่นยำเนื่องจากสามารถทำงานร่วมกับทั้งสองตัวอย่างเฉพาะระบบโดยไม่จำเป็นต้องเปลี่ยนรหัส
Scott Gigante

rootdir = "usr" if nix else "c:"การแก้ปัญหานี้มากเช่นการโพสต์ก่อนหน้านี้ว่าแรงบันดาลใจมันยังคงอาศัยอยู่กับการตั้งค่าเช่น rootdir แต่ยิ่งทำงานได้ตรงและแม่นยำมากขึ้นrootdir = "/usr" if nix else "c:\\"เช่นกันโดยไม่ต้องos.sepผาดโผนและเกาหัวตามมา ไม่มีอันตรายที่ไดเร็กทอรีรูทบน * nix จะเริ่มต้นด้วยสิ่งอื่นใดนอกจากสแลชไปข้างหน้าหรือ Windows จะมีไดเร็กทอรีรูทที่ตั้งชื่อโดยไม่มีเครื่องหมายจุดคู่และแบ็กสแลชต่อท้าย (เช่นใน Win เชลล์คุณไม่สามารถทำได้cd c:คุณ ต้องระบุแบ็กสแลชต่อท้าย) แล้วทำไมต้องแกล้งทำเป็นอย่างอื่น?
Michael Ekoka

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 )
Cecil Curry

ฉันไม่สามารถตอบคำถามนี้เกี่ยวกับ windows ได้เนื่องจากฉันไม่สามารถเข้าถึงเครื่อง windows ได้ แต่ฉันเดาว่าพฤติกรรมของ python เกี่ยวกับคำถามนี้ไม่ได้เปลี่ยนไป อย่างไรก็ตามคำสั่งนี้ไม่เป็นความจริงสำหรับการใช้งาน Linux เนื่องจากคำสั่งแรกส่งคืนเส้นทางโดยไม่มีตัวคั่นชั้นนำ (หรือที่เรียกว่าไดเรกทอรีราก) ในขณะที่คำสั่งที่สองจะส่งคืนพา ธ รวมถึงตัวคั่นชั้นนำ
จอร์เจีย

ดังนั้นฉันจึงไม่ชอบคำตอบของฉันเกี่ยวกับคำถามนี้อีกต่อไป แต่ฉันก็ไม่ชอบพฤติกรรมของ python เกี่ยวกับเรื่องนี้
จอร์เจีย

@Cecil ฉันอยู่ในคำถามนี้ในขณะนี้เนื่องจากปัญหาเดียวกัน ...
joshmcode

5

ในการเข้าร่วมเส้นทาง windows ให้ลอง

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

โดยพื้นฐานแล้วคุณจะต้องหนีจากการเฉือน


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))

2
ใช่ใช่มันชัดเจนกว่านั้น ทำไมไม่ใช้ regexes ในขณะที่คุณทำอยู่ หรือเรียกสคริปต์ perl และประมวลผลผลลัพธ์?
Jean-François Fabre

ฉันไม่คิดว่ามันเป็นความคิดที่ดีเพราะ os.path.join เป็นความหมายที่ดีทีเดียว ... ดังนั้นคุณจะเห็นมันในรหัสและเข้าใจทันทีว่าเกิดอะไรขึ้น
SenhorLucas

0

ตอบความคิดเห็นของคุณ: "the others '//' 'c:', 'c: \\' ไม่ทำงาน (C: \\ สร้างแบ็กสแลชสองตัว, C: \ ไม่ทำงานเลย)"

บน windows ที่ใช้ os.path.join('c:', 'sourcedir') จะเพิ่มแบ็กสแลชสองตัวที่\\ด้านหน้าของแหล่งที่มาโดยอัตโนมัติ

เมื่อต้องการแก้ไขเส้นทางที่เป็นงูหลามทำงานบน Windows ยังมีเครื่องหมายทับ -> '/'เพียงแค่เพิ่ม.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.splitdrivet+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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.