Python os.path.join di Windows

99

Saya mencoba belajar python dan saya membuat program yang akan menampilkan skrip. Saya ingin menggunakan os.path.join, tetapi saya cukup bingung. Menurut dokumen jika saya mengatakan:

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

Saya mengerti "C:sourcedir". Menurut dokumen, ini normal kan?

Tetapi ketika saya menggunakan perintah copytree, Python akan menampilkannya dengan cara yang diinginkan, misalnya:

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

Ini kode kesalahan yang saya dapatkan:

WindowsError: [Error 3] Sistem tidak dapat menemukan jalur yang ditentukan: 'C: src /*.*'

Jika saya membungkusnya os.path.joindengan os.path.normpathsaya mendapatkan kesalahan yang sama.

Jika ini os.path.jointidak bisa digunakan dengan cara ini, maka saya bingung untuk tujuannya.

Menurut halaman yang disarankan oleh Stack Overflow, garis miring tidak boleh digunakan dalam penggabungan — itu benar, menurut saya?

Frank E.
sumber

Jawaban:

60

Windows memiliki konsep direktori saat ini untuk setiap drive. Karena itu, "c:sourcedir"berarti "bersumber" di dalam direktori C: saat ini, dan Anda harus menentukan direktori absolut.

Semua ini harus berfungsi dan memberikan hasil yang sama, tetapi saya tidak memiliki VM Windows yang diaktifkan saat ini untuk memeriksa ulang:

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

sumber
8
os.path.join ('C: /', 'source') berfungsi seperti yang diharapkan. Terima kasih banyak, Pak :) yang lainnya '//' 'c:' 'c: \\' tidak berfungsi (C: \\ membuat dua garis miring terbalik, C: \ tidak berfungsi sama sekali) Terima kasih lagi ghostdog74 , Smashery, dan Roger Pate. Saya berhutang budi :)
Frank E.
Maaf, jeda baris tidak disimpan dalam komentar, itu terlihat sangat berantakan
Frank E.
Bahkan jika ini berhasil dalam beberapa kasus, jawaban dari @AndreasT adalah solusi yang jauh lebih baik. Menggunakan os.sep akan memilih antara / dan \ bergantung pada OS.
SenhorLucas
Apakah ada gunanya menggunakan os.path.joinatau os.sepjika Anda tetap akan menentukannya c:? c:tidak masuk akal di OS lain.
n nothing101
semua solusi ini hanya memuaskan sebagian. Anda boleh menambahkan pemisah secara manual jika Anda memiliki satu kasus tertentu, tetapi jika Anda ingin melakukannya secara terprogram, apa kriteria yang os.path.join('c:','folder')berfungsi secara berbeda os.path.join('folder','file')? Apakah karena :atau karena 'c: `adalah drive?
Vincenzooo
125

Untuk lebih bertele-tele, jawaban yang paling konsisten dari python doc adalah:

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

Karena Anda juga membutuhkan os.sep untuk jalur root posix:

mypath = os.path.join(os.sep, 'usr', 'lib')
AndreasT
sumber
5
Maafkan ketidaktahuan saya - Sepertinya kodenya masih bervariasi antara Windows dan Linux, lalu apa yang membuatnya os.seplebih unggul?
pianoJames
3
Harap perhatikan snafu ini saat mencoba menyuntikkan os.sep. Ini hanya berfungsi setelah huruf drive kosong. >>> os.path.join ("C: \ goodbye", os.sep, "temp") 'C: \\ temp'
Jobu
1
@pianoJames jawaban saya dibangun dari yang satu ini untuk memberikan solusi sistem-agnostik: stackoverflow.com/a/51276165/3996580
Scott Gigante
Saya tidak mengerti maksud dari semua solusi "bertele-tele" ini. os.sepberguna saat Anda ingin memanipulasi jalur tanpa membuat asumsi tentang pemisah. Tidak ada gunanya digunakan dengan os.path.join()karena sudah mengetahui pemisah yang tepat. Ini juga tidak ada gunanya jika Anda akhirnya perlu secara eksplisit menentukan direktori root berdasarkan nama (seperti yang Anda lihat di contoh Anda sendiri). Mengapa "c:" + os.sepbukannya sederhana "c:\\", atau os.sep + "usr"bukannya sederhana "/usr"? Juga perhatikan bahwa di Win shells Anda tidak bisa cd c:tetapi Anda bisa cd c:\ , menunjukkan bahwa nama root sebenarnya c:\ .
Michael Ekoka
13

Alasannya os.path.join('C:', 'src')tidak berfungsi seperti yang Anda harapkan adalah karena sesuatu di dokumentasi yang Anda tautkan:

Perhatikan bahwa di Windows, karena ada direktori saat ini untuk setiap drive, os.path.join ("c:", "foo") mewakili jalur relatif ke direktori saat ini di drive C: (c: foo), bukan c : \ foo.

Seperti yang dikatakan anjing hantu, Anda mungkin menginginkannya mypath=os.path.join('c:\\', 'sourcedir')

Smashery
sumber
12

Untuk menjadi bertele-tele, mungkin tidak baik menggunakan hardcode baik / atau \ sebagai pemisah jalur. Mungkin ini yang terbaik?

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

atau

mypath = os.path.join('c:' + os.sep, 'sourcedir')
Matt Ball
sumber
12

Untuk solusi sistem-agnostik yang bekerja pada Windows dan Linux, apa pun jalur inputnya, seseorang dapat menggunakannya os.path.join(os.sep, rootdir + os.sep, targetdir)

Di Windows:

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

Di Linux:

>>> os.path.join(os.sep, "usr" + os.sep, "lib")
'/usr/lib'
Scott Gigante
sumber
1
Terima kasih! Ini bahkan lebih berguna karena tidak menderita getcha yang @Jobu sebutkan sebelumnya: os.path.join (os.sep, "C: \\ a" + os.sep, "b") mengembalikan "C: \\ a \\ b "di Windows.
pianoJames
1
Bagaimana salah satu dari contoh sistem ini agnostik? c:tidak ada di * nix, dan usrtidak ada di windows ..
naught101
Pemanggilan fungsi os.path.join(os.sep, rootdir + os.sep, targetdir)bersifat agnostik sistem karena ia bekerja dengan kedua contoh khusus sistem tersebut, tanpa perlu mengubah kodenya.
Scott Gigante
Solusi ini, seperti posting sebelumnya yang menginspirasinya, masih bergantung pada pengaturan rootdir seperti rootdir = "usr" if nix else "c:". Tapi yang lebih langsung dan akurat rootdir = "/usr" if nix else "c:\\"bekerja dengan baik, tanpa os.sepakrobat dan garukan kepala berikutnya. Tidak ada bahaya bahwa direktori root pada * nix akan dimulai dengan apa pun selain garis miring, atau bahwa Windows akan memiliki direktori root yang diberi nama tanpa tanda titik dua dan garis miring terbalik (misalnya dalam kerangka Win, Anda tidak dapat melakukannya begitu saja cd c:, Anda perlu menentukan garis miring terbalik), jadi mengapa berpura-pura sebaliknya?
Michael Ekoka
7

Saya akan mengatakan ini adalah bug python (windows).

Mengapa bug?

Saya pikir pernyataan ini seharusnya True

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

Tapi itu ada Falsedi mesin windows.

georg
sumber
1
Saya cenderung setuju bahwa itu merupakan bug Python. Apakah masih demikian? ( Ditulis dari masa depan utopia yang mulia di akhir 2015. )
Cecil Curry
Saya tidak dapat menjawab pertanyaan ini sehubungan dengan windows, karena saya tidak memiliki akses ke mesin windows, tetapi saya kira perilaku python mengenai pertanyaan ini tidak berubah. Bagaimanapun, pernyataan ini juga tidak benar untuk implementasi Linux, karena pernyataan pertama mengembalikan jalur tanpa pemisah utama (alias direktori root), sedangkan pernyataan kedua mengembalikan jalur termasuk pemisah utama.
georg
Jadi saya sebenarnya tidak menyukai jawaban saya tentang pertanyaan ini lagi. Tapi saya juga tidak suka perilaku python tentang ini.
georg
@Cecil Saya sedang dalam pertanyaan ini sekarang karena masalah yang sama ... tampaknya masih demikian.
joshmcode
5

untuk bergabung dengan jalur windows, coba

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

pada dasarnya, Anda harus menghindari garis miring

anjing hantu74
sumber
4

Anda memiliki beberapa kemungkinan pendekatan untuk menangani jalur di Windows, dari yang paling keras kode (seperti menggunakan literal string mentah atau garis miring terbalik) hingga yang paling kecil. Berikut ini beberapa contoh yang akan berfungsi seperti yang diharapkan. Gunakan apa yang lebih sesuai dengan kebutuhan Anda.

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
Marco Gomez
sumber
0

Setuju dengan @ georg-

Saya akan mengatakan mengapa kita membutuhkan orang lumpuh os.path.join- lebih baik digunakanstr.join atau unicode.joinmisalnya

sys.path.append('{0}'.join(os.path.dirname(__file__).split(os.path.sep)[0:-1]).format(os.path.sep))
SIslam
sumber
2
ya, benar, itu waaaaayy lebih jelas seperti itu. Mengapa tidak menggunakan regex saat Anda melakukannya? atau panggil skrip perl dan proses hasilnya?
Jean-François Fabre
Menurut saya itu bukan ide yang bagus karena os.path.join adalah semantik yang cukup bagus ... Jadi Anda melihatnya dalam kode dan langsung memahami apa yang sedang terjadi.
SenhorLucas
0

menjawab komentar Anda: "yang lain '//' 'c:', 'c: \\' tidak berfungsi (C: \\ membuat dua garis miring terbalik, C: \ tidak berfungsi sama sekali)"

Pada jendela yang menggunakan os.path.join('c:', 'sourcedir') secara otomatis akan menambahkan dua garis miring terbalik \\di depan sumber .

Untuk menyelesaikan jalur, karena python berfungsi di windows juga dengan garis miring ke depan -> '/' , cukup tambahkan .replace('\\','/')dengan os.path.joinseperti di bawah ini: -

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

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

keluaran: 'C: / temp'

Pratul
sumber
0

Solusi yang diusulkan menarik dan menawarkan referensi yang baik, namun hanya sebagian yang memuaskan. Anda boleh menambahkan pemisah secara manual saat Anda memiliki kasus tertentu atau Anda mengetahui format string masukan, tetapi mungkin ada kasus di mana Anda ingin melakukannya secara terprogram pada masukan umum.

Dengan sedikit percobaan, saya yakin kriterianya adalah bahwa pembatas jalur tidak ditambahkan jika segmen pertama adalah huruf drive, yang berarti satu huruf diikuti oleh titik dua, tidak peduli apakah itu sesuai dengan unit nyata.

Sebagai contoh:

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

Cara mudah untuk menguji kriteria dan menerapkan koreksi jalur dapat menggunakan os.path.splitdrivemembandingkan elemen pertama yang dikembalikan ke nilai pengujian, seperti t+os.path.sep if os.path.splitdrive(t)[0]==t else t.

Uji:

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

itu mungkin dapat ditingkatkan menjadi lebih kuat untuk ruang tambahan, dan saya telah mengujinya hanya di windows, tapi saya harap ini memberi gambaran. Lihat juga Os.path: dapatkah Anda menjelaskan perilaku ini? untuk detail menarik tentang sistem selain jendela.

Vincenzooo
sumber