Python betiği ile aynı dizindeki bir dosyayı güvenilir bir şekilde açma


157

Şu anda çalışan Python betiği ile aynı dizinde bulunan dosyaları,

open("Some file.txt", "r")

Ancak, komut dosyasını Windows'ta çift tıklatarak çalıştırıldığında, dosyayı yanlış dizinden açmaya çalışacağını keşfettim.

O zamandan beri formun bir komutunu kullandım

open(os.path.join(sys.path[0], "Some file.txt"), "r")

ne zaman bir dosya açmak istesem. Bu benim özel kullanımım için çalışıyor, ancak sys.path[0]başka bir kullanım durumunda başarısız olup olmayacağından emin değilim .

Benim sorum: Şu anda çalışan Python betiği ile aynı dizinde bir dosyayı açmanın en iyi ve en güvenilir yolu nedir?

İşte şimdiye kadar anlayabildiğim:

  • os.getcwd()ve os.path.abspath('')komut dosyası dizinini değil "geçerli çalışma dizinini" döndürün.

  • os.path.dirname(sys.argv[0])ve os.path.dirname(__file__)kodu çağırmak için kullanılan yolu göreceli veya boş olabilir (kod cwd'de ise). Ayrıca, __file__komut IDLE veya PythonWin çalıştırıldığında yok.

  • sys.path[0]ve os.path.abspath(os.path.dirname(sys.argv[0]))komut dosyası dizinini döndürüyor gibi görünüyor. Bu ikisi arasında herhangi bir fark olup olmadığından emin değilim.

Düzenle:

Ben sadece ne yapmak istiyorum daha iyi "içeren modülü ile aynı dizinde bir dosya açmak" olarak tarif olacağını fark ettim. Başka bir deyişle, başka bir dizinde yazdığım bir modülü içe aktarırsam ve bu modül bir dosya açarsa, modülün dizinindeki dosyayı aramasını istiyorum. Bulduğum hiçbir şeyin bunu yapabileceğini sanmıyorum ...

Yanıtlar:


199

Her zaman kullanıyorum:

__location__ = os.path.realpath(
    os.path.join(os.getcwd(), os.path.dirname(__file__)))

join()Çağrı Geçerli çalışma dizini prepends ama dokümantasyon bazı yol mutlak ise, bunun sol tüm diğer yollar bırakılır söylüyor. Bu nedenle, mutlak bir yol döndürdüğünde getcwd()bırakılır dirname(__file__).

Ayrıca, realpathçağrı varsa sembolik bağlantıları da çözer. Bu, Linux sistemlerinde setuptools ile dağıtım yaparken sorunları önler (komut dosyaları /usr/bin/- en azından Debian'a bağlanır).

Aynı klasördeki dosyaları açmak için aşağıdakileri kullanabilirsiniz:

f = open(os.path.join(__location__, 'bundled-resource.jpg'));
# ...

Bunu hem Windows hem de Linux'ta birkaç Django uygulamasıyla kaynakları bir araya getirmek için kullanıyorum ve bir cazibe gibi çalışıyor!


4
Eğer __file__kullanılamaz, daha sonra kullanmak sys.argv[0]yerine dirname(__file__). Gerisi beklendiği gibi çalışmalıdır. Kullanmayı seviyorum __file__çünkü kütüphane kodunda sys.argv[0], özellikle bazı 3. taraf komut dosyası ile içe aktarılmışsa, kodunuzu hiç göstermeyebilir.
André Caron

1
Buradaki sorun, çalıştırılmakta olan dosya doğrudan kesiciden mi yoksa içe aktarılmışsa değişecektir. File ve
sys.argv

Öyleyse Zimm3r'in cevabında tanımlanan varyasyonun realpath( join( getcwd(), dirname(__file__) ))burada tarif edilen şekilde kullanılarak giderildiğini söylemek doğru mu?
pianoJames

44

Python belgelerinden alıntı yapmak için:

Program başlangıcında başlatıldığı gibi, bu listenin ilk öğesi olan yol [0], Python yorumlayıcısını çağırmak için kullanılan komut dosyasını içeren dizindir. Kod dizini mevcut değilse (örneğin, yorumlayıcı etkileşimli olarak çağrılırsa veya kod standart girdiden okunursa), [0] yolu, Python'u önce geçerli dizindeki modülleri aramaya yönlendiren boş dizedir. Komut dosyası dizininin PYTHONPATH sonucunda girilen girdilerden önce eklendiğine dikkat edin.

sys.path [0] aradığınız şeydir.


10
Ve dosyanın tam yolu için: os.path.join(sys.path[0], 'some file.txt'). Bu, tüm sistemlerde boşlukları ve eğik çizgileri doğru şekilde işlemelidir.
Jacktose

İlk soruya verilen bu cevap, DÜZENLEME sonrası cevap değil.
mcoolive

22

Tamam işte yaptığım şey

sys.argv her zaman terminalde yazdığınız veya python.exe veya pythonw.exe ile yürütürken dosya yolu olarak kullandığınız şeydir

Örneğin, text.py dosyasını çeşitli şekillerde çalıştırabilirsiniz, her biri size farklı bir yanıt verir ve size her zaman python'un yazıldığı yolu verir.

    C:\Documents and Settings\Admin>python test.py
    sys.argv[0]: test.py
    C:\Documents and Settings\Admin>python "C:\Documents and Settings\Admin\test.py"
    sys.argv[0]: C:\Documents and Settings\Admin\test.py

Tamam böylece dosya adını alabilirsiniz, büyük bir anlaşma, şimdi uygulama dizini almak için os.path, özellikle abspath ve dirname kullanın

    import sys, os
    print os.path.dirname(os.path.abspath(sys.argv[0]))

Bu çıktı:

   C:\Documents and Settings\Admin\

python test.py veya "C: \ Documents and Settings \ Admin \ test.py" yazdığınızda, bunu her zaman çıktılar

__File__ kullanmayla ilgili sorun Bu iki dosyayı göz önünde bulundurun test.py

import sys
import os

def paths():
        print "__file__: %s" % __file__
        print "sys.argv: %s" % sys.argv[0]

        a_f = os.path.abspath(__file__)
        a_s = os.path.abspath(sys.argv[0])

        print "abs __file__: %s" % a_f
        print "abs sys.argv: %s" % a_s

if __name__ == "__main__":
    paths()

import_test.py

import test
import sys

test.paths()

print "--------"
print __file__
print sys.argv[0]

"Python test.py" çıktısı

C:\Documents and Settings\Admin>python test.py
__file__: test.py
sys.argv: test.py
abs __file__: C:\Documents and Settings\Admin\test.py
abs sys.argv: C:\Documents and Settings\Admin\test.py

"Python test_import.py" çıktısı

C:\Documents and Settings\Admin>python test_import.py
__file__: C:\Documents and Settings\Admin\test.pyc
sys.argv: test_import.py
abs __file__: C:\Documents and Settings\Admin\test.pyc
abs sys.argv: C:\Documents and Settings\Admin\test_import.py
--------
test_import.py
test_import.py

Gördüğünüz gibi dosya size her zaman çalıştırıldığı python dosyasını verir, burada sys.argv [0] olarak her zaman yorumlayıcıdan çalıştırdığınız dosyayı verir. İhtiyaçlarınıza bağlı olarak hangisinin ihtiyaçlarınıza en uygun olduğunu seçmeniz gerekecektir.


3
Bu, uygulamanın belgeleri yansıttığını gösteren ayrıntılı bir kanıttır. __file__olduğu sözde "her zaman geçerli dosyaya sana yolu vermek" ve sys.argv[0]edilir sözde "her zaman süreci başlattı script yolunu vermek" için. Her durumda, __file__çağrılan komut dosyasında kullanmak size her zaman kesin sonuçlar verir.
André Caron

__file__Komut dosyasının en üst düzeyinde referansınız varsa , beklendiği gibi çalışır.
Matthew Schinckel


-3

Bunu şu şekilde yaparım:

from os.path import abspath, exists

f_path = abspath("fooabar.txt")

if exists(f_path):
    with open(f_path) as f:
        print f.read()

Yukarıdaki kod abspath kullanarak dosyaya mutlak bir yol oluşturur ve normpath(join(os.getcwd(), path))[pydocs'tan] kullanmaya eşdeğerdir . Daha sonra bu dosyanın gerçekten var olup olmadığını kontrol eder ve daha sonra açmak için bir bağlam yöneticisi kullanır, böylece dosya tanıtıcısında kapatmayı hatırlamak zorunda kalmazsınız. IMHO, bu şekilde yapmak uzun vadede size çok fazla acı kazandıracak.


Bu posterin sorusuna cevap vermiyor. dln385 özellikle os.path.abspathkomut dosyası geçerli dizinde değilse, komut dosyasıyla aynı klasördeki dosyaların yollarını çözmediğini söyledi .
André Caron

AH! Kullanıcı bu komut dosyası kendi PYTHONPATH bir şey modül dir DEĞİL okumak istedikleri dosya ile aynı direk çalıştırdığı varsayılır . Bana varsayımlar yapmayı öğretir ...
dcolish

abspath, python çalışma zamanının böyle bir işlevi kullanarak OS dosya sisteminde arama yapması imkansız olduğu için çalışmaz.
akshat thakar
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.