Menu

Python'da Dosya Var mı Kontrolü: os.path, pathlib ve try/except

Python'da bir dosyanın var olup olmadığını kontrol etmenin üç yolu: os.path.exists ve isfile, pathlib'in Path.exists ve is_file metotları ve dosyayı try/except FileNotFoundError içinde açmak.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

Kısa Cevap

Bir dosyanın var olup olmadığını kontrol etmek için standart kütüphanedeki os.path.isfile()'ı kullan. Yol var olan normal bir dosyayı gösteriyorsa True, aksi halde False döner. Olmayan bir yol için asla hata fırlatmaz.

/home/ada/notes.txt ya da C:\Users\Ada\notes.txt gibi mutlak bir yol vermediğin sürece yollar, programın çalıştığı klasöre (geçerli çalışma dizinine) göre değerlendirilir.

Sayfanın geri kalanı bu soruyu sormanın diğer yollarını, aralarındaki farkları ve soruyu hiç sormaman gereken durumu anlatıyor.

os.path.exists, isfile ve isdir

os.path modülünde birbirine yakın üç kontrol var ve her biri biraz farklı bir soruyu cevaplıyor:

FonksiyonŞu durumda True döner
os.path.exists(p)var olan herhangi bir şey: bir dosya, bir dizin ya da çalışan bir sembolik bağlantı
os.path.isfile(p)var olan normal bir dosya
os.path.isdir(p)var olan bir dizin

Fark, işin içine bir dizin girdiği anda ortaya çıkar:

Çıktı:

reports True False True
reports/summary.txt True True False
reports/old.txt False False False

reports bir klasör olduğu halde os.path.exists("reports") True döner. Kodun bu yolu bir dosya olarak okumak üzereyse exists yanlış kontroldür: bir dizin bu kontrolü geçer ve ardından open("reports") başarısız olur (Linux ve macOS'ta IsADirectoryError, Windows'ta PermissionError ile). Kastettiğin bir dosyaysa isfile, bir klasörse isdir seç.

Bu üç os.path fonksiyonu hakkında iki ayrıntı daha:

  • Sembolik bağlantılar takip edilir. Gerçek bir dosyayı gösteren bir bağlantı dosya sayılır; bozuk bir bağlantı (hedefi silinmiş) üçünden de False alır.
  • Python'un bir klasörün içine bakma izni yoksa kontrol PermissionError fırlatmak yerine False döner. Yani False, tam olarak "yok" değil, "bulunamadı ya da erişilemedi" demektir.

pathlib ile Kontrol

pathlib, standart kütüphanedeki nesne yönelimli yol API'sidir ve yeni kodların çoğu onu kullanır. Bir Path nesnesinde aynı üç kontrol metot olarak bulunur:

Path.exists(), Path.is_file() ve Path.is_dir(), os.path.exists, isfile ve isdir gibi davranır. / operatörü yol parçalarını işletim sistemine uygun ayırıcıyla birleştirir, bu yüzden folder / "summary.txt" Windows, macOS ve Linux'ta aynı şekilde çalışır. Path nesneleriyle okuma ve yazma için dosya işlemleri sayfasına bak.

Hangisini kullanmalısın? Kodunun geri kalanı zaten Path nesneleriyle çalışıyorsa pathlib'de kal. Düz string'ler ve os fonksiyonlarıyla çalışıyorsan os.path.isfile da aynı derecede doğrudur. İkisi aynı cevapları verir.

Önce Kontrol Etmek Neden Yanlış Olabilir

Bir dosyanın var olup olmadığını kontrol etmenin en yaygın nedeni, onu hemen ardından açmaktır:

import os

if os.path.isfile("config.txt"):
    with open("config.txt") as f:      # dosya bu arada silinmiş olabilir
        settings = f.read()
else:
    settings = ""

Burada bir boşluk var. isfile() çağrısı ile open() çağrısı arasında başka bir program, başka bir thread ya da kullanıcı dosyayı silebilir veya adını değiştirebilir. Kontrol True dedi, açma yine de başarısız oldu ve programın yine FileNotFoundError ile çöktü. Bu boşluğa yarış durumu (race condition) ya da "kontrol zamanından kullanım zamanına" (time of check to time of use) denir. Kendi dizüstü bilgisayarında nadirdir, ama birkaç sürecin aynı klasörü paylaştığı yoğun bir sunucuda çok daha sık görülür.

Çözüm, ayrı kontrolü atlayıp kontrolü open()'a bırakmaktır. Dosya yoksa Python FileNotFoundError fırlatır, sen de bunu except'te ele alırsın:

Çıktı:

theme=dark
(no settings file, using defaults)

Artık iki işlem yerine tek işlem var, yani yarışacak bir şey kalmadı. Python topluluğunda bu tarzın bir adı var: EAFP, "easier to ask forgiveness than permission" (izin istemektense af dilemek daha kolaydır). Karşıt tarz, yani önce kontrol etmek, LBYL'dir: "look before you leap" (atlamadan önce bak). Python dosya işlerinde EAFP'ye yakındır, çünkü dosyayı açtığın anda cevabı bilen tek şey işletim sistemidir.

Ters gidebilecek tek şey FileNotFoundError değildir. Dizin olan bir yol IsADirectoryError (Windows'ta PermissionError), okuyamadığın bir dosya da PermissionError fırlatır. Üçü de OSError'ın alt sınıflarıdır, bu yüzden except OSError: "açılamadı" durumlarının hepsini birden yakalar. Belirli bir hatayı yakalamakla bütün bir aileyi yakalamak arasında nasıl seçim yapacağını istisnalar sayfası anlatıyor.

Düz Bir Kontrolün Yeterli Olduğu Durumlar

Önce kontrol etmek her durumda yanlış değildir. Yalnızca cevaba ihtiyacın olduğunda ve bir sonraki satırda dosya üzerinde işlem yapmayacağında doğru araçtır:

  • hangi mesajın gösterileceğini seçmek ("3 kayıtlı oyun bulundu")
  • uzun bir işe başlamadan önce kullanıcının yazdığı yolu doğrulamak
  • daha önce yapılmış bir işi atlamak (eskimiş bir cevabın tek bedeli işin tekrarlanmasıdır)

Temel kural: dosyayı açacak, okuyacak, yazacak ya da sileceksen bunu try içinde yap. Yalnızca bilmek istiyorsan isfile() ya da Path.is_file() yeterlidir.

Bir Dosyayı Yalnızca Yoksa Oluşturmak

Ters soru da karşına çıkar: "bu dosyayı yaz, ama var olan bir dosyanın üzerine asla yazma". Akla ilk gelen sürüm, öncekiyle aynı yarışı taşır:

if not os.path.exists("report.txt"):
    with open("report.txt", "w") as f:   # başka bir süreç dosyayı önce oluşturabilir
        f.write("new report\n")

"x" modu (özel oluşturma) iki adımı tek adımda yapar. Dosyayı oluşturur, o ad alınmışsa FileExistsError fırlatır:

Çıktı:

attempt 1: created report.txt
attempt 2: report.txt already exists, left it alone

Klasörler için os.makedirs(path, exist_ok=True) ve Path(path).mkdir(parents=True, exist_ok=True) dizini ve eksik üst dizinleri oluşturur, dizin zaten varsa hiçbir şey yapmaz. Önce isdir() çağırmana gerek yok.

Sık Yapılan Hatalar

  • Bir dosyayı kastederken exists() kullanmak. Aynı adı taşıyan bir dizin de kontrolü geçer. isfile() ya da Path.is_file() kullan.
  • Göreli yolların nereden başladığını unutmak. "data.txt" geçerli çalışma dizininde aranır; bu, programı başlattığın yerdir ve betiğin bulunduğu klasör olmak zorunda değildir. Betiğin yanındaki bir dosyayı bulmak için yolu Path(__file__).parent'tan kur.
  • Önce kontrol edip sonra açmak. Dosya arada değişebilir. try içinde aç ve FileNotFoundError'ı ele al.
  • Her istisnayı yakalamak. open() etrafındaki except Exception:, dosyayı okuyan koddaki yazım hatalarını ve bug'ları da gizler. FileNotFoundError ya da OSError yakala.

Sıkça Sorulan Sorular

Python'da bir dosyanın var olup olmadığını nasıl kontrol ederim?

os modülünü içe aktar ve os.path.isfile("data.txt") çağır; yalnızca var olan normal bir dosya için True döner. pathlib ile bu Path("data.txt").is_file() olur. Aynı adı taşıyan bir dizin de sayılsın istiyorsan os.path.exists() ya da Path.exists() kullan.

os.path.exists ile os.path.isfile arasındaki fark nedir?

os.path.exists(p) o yoldaki her şey için True döner: bir dosya, bir dizin ya da gerçek bir yeri gösteren bir sembolik bağlantı. os.path.isfile(p) yalnızca normal bir dosya için True döner, yani bir dizin için False verir. Dizinler için karşılığı os.path.isdir(p)'dir.

Bir dosyayı açmadan önce var olup olmadığını kontrol etmeli miyim?

Genellikle hayır. Dosya, kontrol ile open() çağrısı arasında silinebilir ya da oluşturulabilir, bu yüzden kontrol hiçbir şeyi garanti etmez. Dosyayı doğrudan try içinde aç ve FileNotFoundError'ı except'te ele al. Ayrı bir varlık kontrolü, yalnızca cevaba ihtiyacın olduğunda doğrudur; örneğin hangi mesajı göstereceğine karar verirken.

Bir dosyayı yalnızca yoksa nasıl oluştururum?

Dosyayı "x" moduyla aç: open("report.txt", "x"). Python dosyayı oluşturur, o adda zaten bir şey varsa FileExistsError fırlatır. Kontrol ve oluşturma tek adımda gerçekleşir, bu yüzden başka bir program araya giremez.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA