Ana içeriğe geç
Kesit Python
Temel · Dosya ve hata

Dosya işlemleri

Veri programdan uzun yaşar: open ve with, okuma-yazma modları, satır satır okuma, CSV metnini elle ayrıştırma ve pathlib ile modern dosya yolu.

Uygulamada aç, 22 alıştırmayı çözÜcretsiz, hesap gerekmez, kurulum yok.

Bu sayfa dersin okuma sürümüdür. Metin bir kutuyu çalıştırmanı ya da adıma geçmeni söylüyorsa dersi uygulamada aç.

Neden önemli?

Program kapanınca değişkenler silinir. Anadolu Market'in sipariş listesi, Ilgaz Bank'ın günlük işlem dökümü ise kalıcı olmalı: diske yazılır, yarın yeniden okunur, başka programlara verilir. İş hayatında verinin büyük bölümü hâlâ düz metin ve CSV dosyalarında dolaşır. Bu derste önce bellekte küçük dosyalar oluşturup okuyacağız; aynı kod bilgisayarındaki gerçek dosyalarda da çalışır.

Tarayıcıdaki dosyalarBu uygulama tarayıcıda çalıştığı için yazdığın dosyalar bellek içi bir dosya sisteminde oluşur; sayfayı yenileyince silinir. Kendi bilgisayarında aynı kod gerçek dosyalar üretir. Alıştırmalarda önce dosyayı kodla yazıp sonra okuyacağız.

open ve with: aç, kullan, kesin kapat

open(yol, mod, encoding="utf-8") bir dosya nesnesi döndürür. with bloğu bittiğinde dosya, hata olsa bile otomatik kapanır. Kapanmayan dosya veri kaybına ve "dosya kullanımda" hatalarına yol açar; bu yüzden hep with kullan.

with open("notlar.txt", "w", encoding="utf-8") as f:
    f.write("Anadolu Market günlük notlar\n")
    f.write("Kulaklık stoğu kritik\n")

with open("notlar.txt", "r", encoding="utf-8") as f:
    icerik = f.read()

print(icerik)
print("Karakter sayısı:", len(icerik))
encoding="utf-8" yazmayı unutmaTürkçe karakterler (ş, ğ, İ) için şart. Windows'ta varsayılan kodlama farklı olabilir ve "ş" yerine bozuk karakterler görürsün. Her open çağrısına ekle.

Dosya modları

ModAdıDosya varsaDosya yoksa
"r"okuma (read)baştan okurFileNotFoundError
"w"yazma (write)içeriği siler, baştan yazaroluşturur
"a"ekleme (append)sonuna ekleroluşturur
"x"yeni oluşturFileExistsErroroluşturur
"rb" / "wb"ikili (binary)resim, PDF gibi metin olmayan dosyalar; encoding verilmez
"w" acımasızdırVar olan dosyayı "w" ile açtığın anda içeriği silinir, henüz hiçbir şey yazmamış olsan bile. Günlük (log) tutuyorsan "a" kullan.
with open("islem.log", "w", encoding="utf-8") as f:
    f.write("09:00 sistem açıldı\n")

with open("islem.log", "a", encoding="utf-8") as f:
    f.write("09:15 sipariş 1001 alındı\n")
    f.write("09:20 sipariş 1002 alındı\n")

with open("islem.log", encoding="utf-8") as f:   # mod verilmezse "r"
    print(f.read())

Satır satır okuma

read() tüm dosyayı tek metin olarak belleğe alır; milyonlarca satırlık bir log için uygun değildir. Dosya nesnesi üzerinde doğrudan for ile dönersen Python satırları teker teker okur. Her satırın sonunda \n gelir; strip() ile temizle.

with open("islem.log", encoding="utf-8") as f:
    for numara, satir in enumerate(f, start=1):
        satir = satir.strip()
        if "sipariş" in satir:
            print(f"{numara}: {satir}")

# Tüm satırları liste olarak almak
with open("islem.log", encoding="utf-8") as f:
    satirlar = f.readlines()
print(len(satirlar), "satır")
print(satirlar[0].rstrip())

CSV'yi elle ayrıştırma

CSV (comma-separated values), her satırın bir kayıt, virgülle ayrılmış her parçanın bir alan olduğu düz metin dosyasıdır; Excel açar, her sistem üretir. İlk satır genelde başlık. Dosyadan okunan her şey metindir; sayısal alanları int/float ile dönüştürmeyi unutma.

csv_metni = """id,musteri,sehir,tutar
1001,Ayşe,Ankara,900.0
1002,Mehmet,İzmir,820.0
1003,Elif,Ankara,930.0
1004,Can,İstanbul,450.0
"""
with open("siparisler.csv", "w", encoding="utf-8") as f:
    f.write(csv_metni)

siparisler = []
with open("siparisler.csv", encoding="utf-8") as f:
    basliklar = f.readline().strip().split(",")
    for satir in f:
        satir = satir.strip()
        if not satir:            # boş satırı atla
            continue
        alanlar = satir.split(",")
        kayit = dict(zip(basliklar, alanlar))
        kayit["id"] = int(kayit["id"])
        kayit["tutar"] = float(kayit["tutar"])
        siparisler.append(kayit)

print(basliklar)
print(siparisler[0])
print("Toplam:", sum(s["tutar"] for s in siparisler))

dict(zip(basliklar, alanlar)) hilesi başlıkla değeri eşleştirip sözlük üretir; sütun sırası değişse bile kod bozulmaz. Alan içinde virgül ya da tırnak varsa (adres gibi) elle split yetmez; o zaman standart csv modülünü kullanırsın, orta seviyede göreceğiz.

Dosyaya rapor yazma

Önceki derste ürettiğin rapor metnini dosyaya yazmak tek satır: f.write(rapor). Birden çok satırı tek seferde yazmak için writelines var ama satır sonlarını kendin eklemelisin; en temizi "\n".join(...) ile metni hazırlayıp yazmaktır.

satirlar = [f"{'Şehir':<10}{'Ciro':>10}", "-" * 20]
for sehir, ciro in [("Ankara", 1830.0), ("İzmir", 820.0), ("İstanbul", 450.0)]:
    satirlar.append(f"{sehir:<10}{ciro:>10,.2f}")

with open("rapor.txt", "w", encoding="utf-8") as f:
    f.write("\n".join(satirlar) + "\n")

with open("rapor.txt", encoding="utf-8") as f:
    print(f.read())

pathlib: dosya yolu bir nesnedir

os.path ile metin birleştirmek yerine pathlib.Path yolu bir nesne olarak taşır; / operatörüyle parçalar birleşir, işletim sistemi farkı (Windows'ta ters bölü) kendiliğinden çözülür. Küçük dosyalar için read_text ve write_text kısayolları with open yazmaktan da kısadır.

from pathlib import Path

klasor = Path("raporlar")
klasor.mkdir(exist_ok=True)          # varsa hata verme
dosya = klasor / "ciro_2024_03.txt"  # yol birleştirme

dosya.write_text("Ankara;1830.00\nİzmir;820.00\n", encoding="utf-8")
print(dosya.exists(), dosya.name, dosya.suffix, dosya.parent)
print(dosya.read_text(encoding="utf-8"))

for p in klasor.glob("*.txt"):       # klasördeki txt dosyaları
    print("bulundu:", p)
Derinleş

Derinleş: dosyalarla günlük iş

Temeli kurdun: open, with, modlar, satır satır okuma, pathlib. Bu bölümde iş hayatında her hafta karşına çıkacak işleri ele alıyoruz: "dosya bulunamadı" hatasının asıl nedeni, yolu parçalarına ayırmak, aynı anda iki dosyayla çalışmak, şubelerden gelen dosyaları birleştirmek ve Excel'den gelen bozuk görünen CSV'ler. İkili (binary) mod, seek, arşivler ve atomik yazmanın ayrıntısı orta seviyedeki İleri dosya işlemleri dersinde; csv ve json modülleri de JSON ve CSV dersinde.

Çalışma klasörü: göreli yol nereden başlar?

open("siparisler.csv") yazdığında Python dosyayı betiğin yanında değil, çalışma klasöründe (current working directory) arar. Terminalde hangi klasördeyken python komutunu verdiysen orasıdır. VS Code'da "Çalıştır" düğmesi çoğu zaman proje kökünü kullanır; bu yüzden "bende çalışıyordu" hatalarının yarısı buradan çıkar.

from pathlib import Path
import os

print("Çalışma klasörü:", Path.cwd())
print("Aynı bilgi os ile:", os.getcwd())

yol = Path("olmayan_rapor.csv")
print("Göreli yol:", yol)
print("Python aslında burada arayacak:", yol.resolve())
print("Var mı?", yol.exists())
FileNotFoundError aldığında üç soru1) Path.cwd() nerede? 2) Path(yol).resolve() tam olarak neyi gösteriyor? 3) Dosya adında gizli uzantı var mı (Windows "rapor.csv.txt" diye kaydetmiş olabilir)? Bu üçünü yazdırmak tahmin yürütmekten hızlıdır.

Yolu parçalarına ayır: Path'in sorgu araçları

Dosya adlarıyla metin işlemi (split("."), replace) yapmak kırılgandır: "rapor.v2.csv" gibi adlar seni şaşırtır. Path nesnesi her parçayı ayrı özellik olarak verir.

İfade"veri/2026/satis_ekim.csv" için sonuçNe işe yarar?
p.namesatis_ekim.csvKlasörsüz tam dosya adı
p.stemsatis_ekimUzantısız ad; rapor başlığı, sözlük anahtarı
p.suffix.csvUzantı (noktasıyla)
p.parentveri/2026Bulunduğu klasör
p.with_suffix(".json")veri/2026/satis_ekim.jsonAynı yerde farklı uzantılı çıktı
p.with_name("ozet.txt")veri/2026/ozet.txtAynı klasörde başka dosya
p.is_file() / p.is_dir()True / FalseVar mı ve türü ne?
p.stat().st_sizebayt cinsinden boyutBoş dosyayı atlamak
p.unlink(missing_ok=True)dosyayı silerYoksa hata vermeden
klasor.iterdir() / klasor.rglob("*.csv")içerik / alt klasörler dahil aramaToplu işleme
from pathlib import Path

klasor = Path("veri") / "2026"
klasor.mkdir(parents=True, exist_ok=True)     # ara klasörleri de oluştur
p = klasor / "satis_ekim.csv"
p.write_text("id,tutar\n1,250\n2,400\n", encoding="utf-8")

print(p.name, "|", p.stem, "|", p.suffix)
print("Klasör:", p.parent.as_posix())
print("JSON çıktısı:", p.with_suffix(".json").as_posix())
print("Boyut:", p.stat().st_size, "bayt")

for dosya in sorted(Path("veri").rglob("*.csv")):
    print("CSV bulundu:", dosya.as_posix())

mkdir(parents=True, exist_ok=True) ikilisini ezberle: "ara klasörler de yoksa oluştur, varsa sessiz kal". as_posix() yolu her işletim sisteminde eğik çizgiyle (/) yazar; rapor ve log çıktısında tutarlı görünür.

Aynı anda iki dosya: oku, süz, yaz

Tek bir with satırında birden çok dosya açabilirsin. Kaynaktan satır satır okuyup hedefe yazmak, bellekte tüm dosyayı tutmadan "filtre" kurmanın standart yoludur. print(..., file=f) da dosyaya yazar ve satır sonunu kendisi ekler; write ise yalnız metin (str) alır ve \n eklemez.

with open("banka_islem.log", "w", encoding="utf-8") as f:
    f.write("09:01 OK havale 1500\n09:04 HATA zaman aşımı\n09:10 OK eft 320\n09:12 HATA limit aşıldı\n")

hata_sayisi = 0
with open("banka_islem.log", encoding="utf-8") as kaynak, \
     open("hatalar.log", "w", encoding="utf-8") as hedef:
    for satir in kaynak:
        if " HATA " in satir:
            hedef.write(satir)          # satırın kendi \n'i var
            hata_sayisi += 1
    print(f"Toplam {hata_sayisi} hata", file=hedef)   # print satır sonunu ekler

print(open("hatalar.log", encoding="utf-8").read())
n = open("deneme.txt", "w", encoding="utf-8").write("Ankara\n")
print("write dönen değer (yazılan karakter):", n)
write sayı kabul etmezf.write(1500) → TypeError: write() argument must be str, not int. Önce str() ya da f-string kullan: f.write(f"{ciro:.2f}\n"). Ayrıca son örnekteki gibi with kullanmadan açılan dosya kapanmayabilir; o satır yalnızca dönen değeri göstermek için.

Şubelerden gelen dosyaları birleştirmek

Anadolu Market'in her şubesi günlük satışını ayrı CSV olarak gönderiyor; hepsinin başlığı aynı. Birleştirirken başlığı yalnız bir kez yaz, boş satırları atla, kaynak dosyanın adını yeni bir sütun olarak ekle ki sonradan "bu satır hangi şubeden geldi?" sorusu cevaplanabilsin.

from pathlib import Path

gelen = Path("gelen_subeler")
gelen.mkdir(exist_ok=True)
(gelen / "kadikoy.csv").write_text("urun,adet\nkulaklik,3\nkablo,10\n", encoding="utf-8")
(gelen / "cankaya.csv").write_text("urun,adet\nkulaklik,5\n\n", encoding="utf-8")

cikti = ["sube,urun,adet"]
for dosya in sorted(gelen.glob("*.csv")):
    satirlar = dosya.read_text(encoding="utf-8").splitlines()
    for satir in satirlar[1:]:              # başlığı atla
        if satir.strip():
            cikti.append(f"{dosya.stem},{satir}")

Path("tum_subeler.csv").write_text("\n".join(cikti) + "\n", encoding="utf-8")
print(Path("tum_subeler.csv").read_text(encoding="utf-8"))

Excel'den gelen CSV: BOM ve noktalı virgül

Türkçe Excel "CSV (UTF-8)" olarak kaydettiğinde iki sürpriz yapar: ayırıcı virgül değil noktalı virgüldür (çünkü ondalık ayırıcı virgüldür: 1250,50), ve dosyanın başına görünmez bir BOM (byte order mark, \ufeff) karakteri koyar. Sonuç: ilk sütunun adı "id" değil "\ufeffid" olur ve kayit["id"] KeyError verir.

with open("excel_cikti.csv", "w", encoding="utf-8-sig") as f:   # Excel gibi BOM'lu yaz
    f.write("id;musteri;tutar\n1;Ayşe;1250,50\n")

with open("excel_cikti.csv", encoding="utf-8") as f:
    print("utf-8 ile ilk başlık:", repr(f.readline().split(";")[0]))

with open("excel_cikti.csv", encoding="utf-8-sig") as f:
    basliklar = f.readline().strip().split(";")
    alanlar = f.readline().strip().split(";")
kayit = dict(zip(basliklar, alanlar))
kayit["tutar"] = float(kayit["tutar"].replace(".", "").replace(",", "."))
print("utf-8-sig ile:", kayit)
BelirtiNedenÇözüm
İlk sütun adı \ufeffidBOMencoding="utf-8-sig"
Her satır tek alanAyırıcı ;split(";") ya da csv modülünde delimiter=";"
float("1.250,50") ValueErrorTürkçe sayı biçimiÖnce binlik noktayı sil, sonra virgülü noktaya çevir
"ÅŸ" gibi bozuk harflerDosya cp1254/latin ile yazılmışencoding="cp1254" dene
Satırlar arası boş satır (Windows)Çift satır sonucsv modülüyle yazarken newline=""

Basit ayar dosyası okumak

Küçük betikler ayarlarını çoğu zaman anahtar=değer satırlarından oluşan bir dosyada tutar. # ile başlayan satırlar yorumdur. Satırı yalnızca ilk eşittir işaretinden bölmek önemlidir; değerin içinde de = olabilir (split("=", 1)). Daha zengin biçimler (INI, TOML, .env) Yapılandırma dersinde.

Gerçek işteMuhasebe ekibi her sabah bankadan gelen ekstre dosyalarını bir klasöre bırakır; senin betiğin klasörü tarar (glob), yeni dosyaları birleştirir, hatalı satırları ayrı bir dosyaya yazar ve işlenen dosyayı "islenmis" klasörüne taşır (rename). Bu iş akışının her parçasını bu derste gördün. İki altın kural: girdiyi asla yerinde değiştirme (yeni dosya üret) ve her çıktı dosyasının adına tarih koy (rapor_2026-10-28.txt), böylece dünkü rapor üzerine yazılmaz.
Uzmanlaş

Büyük dosyada bellek

Satır satır okuma, dosya ne kadar büyük olursa olsun bellekte yalnız bir satır tutar. Bir gigabaytlık log'u read() ile açmak programı çökertebilir; for satir in f ile dakikalar sürse de biter. Orta seviyedeki üreteçler (generator) bu fikri genelleştirir.

Yolu sabit yazma

"C:/Users/ayse/rapor.txt" gibi mutlak yollar başka bilgisayarda çalışmaz. Betiğin bulunduğu klasöre göreli yol kur: Path(__file__).parent / "veri" / "siparisler.csv". Ayarları ortam değişkeninden okumak da yaygındır.

Atomik yazma

Rapor yazılırken elektrik kesilirse yarım dosya kalır. Kurumsal betikler önce geçici dosyaya yazar, sonra Path.replace ile asıl adına taşır; taşıma işlemi ya tamamen olur ya hiç olmaz. Veri kaybının ucuz çözümü budur.

Alıştırmalara geç (22)