Dosyalar ve basit CSV

Şimdiye kadar verilerimizi doğrudan Python kodunun içine yazdık. Program kapandığında veya kod değiştirildiğinde bu değerlerin kalıcı bir kaynağı yoktu. Gerçek uygulamalarda veriler çoğu zaman dosyalardan okunur ve sonuçlar dosyalara yazılır.

Bu hafta metin dosyalarını açmayı, okumayı ve yazmayı; ardından satır ve sütunlardan oluşan basit CSV verilerini işlemeyi öğreneceğiz. Tarayıcıdaki interaktif örneklerde gerçek bilgisayar dosya sistemine erişmek yerine aynı mantığı güvenli biçimde taklit eden bellek içi metinler kullanacağız. Normal Python ortamında kullanılacak gerçek dosya kodunu ayrıca göreceğiz.

Bu hafta neleri yapabilmelisiniz?

Bölümün sonunda:

  • with open(...) yapısının temel amacını açıklayabilmeli,
  • Metin dosyasında "r", "w" ve "a" kiplerini ayırt edebilmeli,
  • encoding="utf-8" ve CSV bağlamında newline="" kullanımının nedenlerini açıklayabilmeli,
  • read(), readlines() ve dosya nesnesi üzerinde satır satır gezinme arasındaki farkı açıklayabilmeli,
  • Dosya yollarının çalışma dizinine göre yorumlandığını açıklayabilmeli,
  • csv modülüyle basit CSV satırlarını okuyabilmeli,
  • csv.DictReader ile sütun adlarını anahtar olarak kullanabilmeli,
  • Virgül dışındaki CSV ayraçlarını delimiter ile belirtebilmeli,
  • BOM içeren UTF-8 CSV dosyalarında utf-8-sig kullanabilmeli,
  • Ondalık virgüllü basit sayısal alanları açık bir dönüşüm kuralıyla işleyebilmeli,
  • Küçük bir CSV veri kümesinden toplam veya filtrelenmiş sonuç üretebilmelisiniz.

Dosya neden gerekir?

Bir programın şu verilerle çalıştığını düşünelim:

puanlar = [70, 82, 91, 65]

Bu liste kodun parçasıdır. Oysa puanların başka bir program tarafından üretilmesi veya kullanıcı tarafından daha önce kaydedilmiş olması mümkündür. Böyle bir durumda veri bir dosyada tutulabilir.

puanlar.txt:

70
82
91
65

Program bu dosyayı okuyup veriyi işleyebilir.

with open(...) ile dosya açmak

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

print(icerik)

Burada:

  • "puanlar.txt" dosya yoludur,
  • "r" okuma kipidir,
  • encoding="utf-8" karakterlerin nasıl çözüleceğini belirtir,
  • as dosya açılan dosya nesnesine verdiğimiz addır.

with bloğu bittiğinde dosya otomatik olarak kapatılır.

Important

Başlangıç düzeyinde dosya açarken with open(...) kalıbını varsayılan yaklaşım olarak kullanacağız.

Okuma, yazma ve ekleme kipleri

Kip Anlam
"r" Dosyayı okumak
"w" Dosyayı yazmak; varsa mevcut içeriği silip yeniden oluşturmak
"a" Dosyanın sonuna içerik eklemek (append)

"w" örneği:

with open("sonuc.txt", "w", encoding="utf-8") as dosya:
    dosya.write("İşlem tamamlandı\n")

"a" örneği:

with open("gunluk.txt", "a", encoding="utf-8") as dosya:
    dosya.write("Yeni kayıt\n")

"a" mevcut içeriği silmeden sonuna ekler. Bu, “rapora yeni satır ekle” türü işlerde kullanışlıdır.

Warning

"w" kipini yanlış dosyada kullanmak mevcut veriyi silebilir. "a" ise her çalıştırmada tekrar ekleme yapar; başlık satırını da her seferinde yazarsanız aynı başlık birden fazla kez oluşabilir. Hangi kipin veri sözleşmesine uygun olduğunu düşünün.

Dosya yolu ve çalışma dizini

open("veriler/puanlar.txt", "r", encoding="utf-8")

bu yolu programın çalışma dizinine göre arar. Dosya bulunamazsa FileNotFoundError oluşabilir.

Hata ayıklarken iki soru önemlidir:

Program hangi dizinden çalışıyor?
Dosya yolu o dizine göre doğru mu?

read(), readlines() ve satır satır okuma

Dosya içeriğini farklı biçimlerde okuyabiliriz.

read() → tek bir string

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

print(type(icerik))  # str

read() dosyanın geri kalanını tek bir string olarak verir.

Bu nedenle:

with open("puanlar.txt", "r", encoding="utf-8") as dosya:
    for deger in dosya.read():
        print(deger)

satırlar üzerinde değil, karakterler üzerinde dolaşır.

readlines() → string listesi

with open("puanlar.txt", "r", encoding="utf-8") as dosya:
    satirlar = dosya.readlines()

print(type(satirlar))  # list

Her liste elemanı bir satır string’idir; çoğu satır sonunda \n bulunur.

Dosya nesnesi üzerinde for → satır satır

with open("puanlar.txt", "r", encoding="utf-8") as dosya:
    for satir in dosya:
        print(satir.strip())

Bu derste satır bazlı işlemlerde çoğunlukla doğrudan for satir in dosya biçimini kullanacağız. Büyük dosya performansı ayrıntılarına girmiyoruz; hedef, hangi yapının karakter, tek string veya satır listesi ürettiğini doğru anlamaktır.

Tarayıcı alıştırmalarında dosya mantığını simüle etmek

StringIO, metni bellek içinde dosya benzeri bir nesne olarak kullanır. Gerçek Python uygulamasında çoğunlukla with open(...) kullanılır.

Alıştırma — satırlardaki sayıları toplayın

Beklenen sonuç 500dür.

deger = int(satir.strip()) ve toplam = toplam + deger kullanabilirsiniz.

from io import StringIO

veri = """120
145
98
137
"""

dosya = StringIO(veri)
toplam = 0

for satir in dosya:
    deger = int(satir.strip())
    toplam = toplam + deger

print(toplam)

CSV nedir?

CSV, tablo biçimindeki verileri düz metin olarak saklamanın yaygın yollarından biridir. Adı “comma-separated values” ifadesinden gelir; ancak ayraç her zaman virgül değildir.

Basit örnek:

ad,puan,bolum
Deniz,78,Bilgisayar
Ayse,92,Siber
Mert,55,Bilgisayar

CSV verisini split(",") ile elle parçalamak tırnak içinde virgül gibi durumlarda hatalı olabilir. Bu nedenle Python’ın standart csv modülünü kullanacağız.

csv.reader ve newline=""

import csv

with open("ogrenciler.csv", "r", encoding="utf-8", newline="") as dosya:
    okuyucu = csv.reader(dosya)

    for satir in okuyucu:
        print(satir)

newline="", dosya satır sonlarının csv modülü tarafından kendi kurallarına göre ele alınmasını sağlar. Özellikle Windows dahil farklı platformlarda CSV okuma/yazmada gereksiz boş satır veya satır sonu dönüşümü sorunlarını önlemek için Python belgelerinde önerilen kalıptır.

Note

newline="" bir CSV ayıracı değildir. Virgül, noktalı virgül gibi sütun ayıracını delimiter belirler; newline ise metin dosyasındaki satır sonlarının işlenmesiyle ilgilidir.

csv.DictReader

import csv

with open("ogrenciler.csv", "r", encoding="utf-8", newline="") as dosya:
    okuyucu = csv.DictReader(dosya)

    for kayit in okuyucu:
        print(kayit["ad"], kayit["puan"])

Her kayit sözlük benzeri bir yapı olarak okunur. CSV’den gelen alan değerleri başlangıçta string olduğu için:

puan = int(kayit["puan"])

gibi dönüşümler gerekir.

CSV satırının DictReader ile okunup tür dönüşümleri yapılmış Python kaydına dönüştürülmesi.

CSV satırından Python kaydına

Türkiye’de Excel’den gelen CSV: ;, BOM ve ondalık virgül

Kendi oluşturduğunuz CSV dosyasında her zaman ders örneğindeki , ayıracını görmeyebilirsiniz. Türkçe bölgesel ayarlarla çalışan Excel ve benzeri tablo uygulamalarında sık karşılaşılan bir biçim şöyledir:

urun;adet;fiyat
Kalem;2;12,5
Defter;3;45,0

Bu dosyada üç ayrı konu vardır.

1. Sütun ayıracı noktalı virgül olabilir

Varsayılan csv.DictReader(dosya) virgül beklerse bütün satırı tek sütun gibi okuyabilir. Ayıracı açıkça verin:

okuyucu = csv.DictReader(dosya, delimiter=";")

2. Dosyanın başında UTF-8 BOM olabilir

Bazı programların dışa aktardığı UTF-8 CSV dosyasının başında BOM bulunabilir. Normal utf-8 ile okunduğunda ilk başlık "ad" yerine görünmez bir karakter taşıyan "\ufeffad" olabilir.

Böyle dosyalarda:

with open("veri.csv", "r", encoding="utf-8-sig", newline="") as dosya:
    okuyucu = csv.DictReader(dosya, delimiter=";")

kullanımı, varsa BOM’u okuma sırasında kaldırır. utf-8-sig, BOM olmayan UTF-8 dosyayı da okuyabilir; fakat dosyanızın gerçek kodlamasını bilmek her zaman daha iyidir.

3. Ondalık ayıracı virgül olabilir

float("12,5")

ValueError üretir; Python’ın float() sözdizimi ondalık nokta bekler. Basit ve sözleşmesi açık bir veri kümesinde yalnızca ondalık virgül kullanıldığını biliyorsanız:

fiyat_metni = kayit["fiyat"]
fiyat = float(fiyat_metni.replace(",", "."))

kullanabilirsiniz.

Bir arada:

import csv

with open("satislar.csv", "r", encoding="utf-8-sig", newline="") as dosya:
    okuyucu = csv.DictReader(dosya, delimiter=";")

    for kayit in okuyucu:
        adet = int(kayit["adet"])
        fiyat = float(kayit["fiyat"].replace(",", "."))
        print(kayit["urun"], adet, fiyat)
Warning

replace(",", ".") yalnızca veri biçiminin ondalık virgül ve binlik ayıracı yok biçiminde olduğunu bildiğiniz basit örneklerde güvenlidir. 1.234,56, 1 234,56 veya farklı bölgesel sayı biçimleri için daha açık bir veri sözleşmesi ya da uygun yerelleştirme aracı gerekir. Amaç “her CSV’yi metin değiştirerek düzeltmek” değildir.

Important

CSV biçimini dosya uzantısından tahmin etmek yerine ayraç, kodlama ve sayısal biçim sözleşmesini belirleyin. Türkiye’deki öğrencinin kendi Excel çıktısıyla karşılaşacağı ;, BOM ve 12,5 durumları bu nedenle normal veri işleme problemleridir; “Python bozuldu” anlamına gelmez.

Tarayıcıda CSV okuma

Alıştırma — geçen öğrencileri sayın

Beklenen sonuç 3tür.

puan = int(kayit["puan"]) ile başlayın.

import csv
from io import StringIO

veri = """ad,puan
Deniz,78
Ayse,92
Mert,55
Ece,60
"""

dosya = StringIO(veri)
okuyucu = csv.DictReader(dosya)
gecen_sayisi = 0

for kayit in okuyucu:
    puan = int(kayit["puan"])
    if puan >= 60:
        gecen_sayisi = gecen_sayisi + 1

print(gecen_sayisi)

CSV’den sözlük listesi üretmek

import csv

ogrenciler = []

with open("ogrenciler.csv", "r", encoding="utf-8", newline="") as dosya:
    okuyucu = csv.DictReader(dosya)

    for kayit in okuyucu:
        ogrenci = {
            "ad": kayit["ad"],
            "puan": int(kayit["puan"]),
            "bolum": kayit["bolum"]
        }
        ogrenciler.append(ogrenci)

Bu noktadan sonra 11. haftadaki liste ve sözlük işleme fonksiyonlarımız yeniden kullanılabilir:

dosyadan okuma
    ↓
türleri dönüştürme
    ↓
program içi veri yapısı
    ↓
hesaplama / filtreleme / raporlama

Çalışma klasörü, göreli yol ve with open kullanımı arasındaki ilişki.

Dosya okuma akışı

Dosyaya yazmak ve eklemek

Yeni rapor oluşturmak:

toplam = 450

with open("rapor.txt", "w", encoding="utf-8") as dosya:
    dosya.write(f"Toplam satış: {toplam:.2f} TL\n")

Mevcut günlük/rapor sonuna yeni satır eklemek:

with open("rapor.txt", "a", encoding="utf-8") as dosya:
    dosya.write("Yeni ölçüm eklendi\n")

Bu hafta csv.DictWriter gibi daha ayrıntılı CSV yazma araçlarını zorunlu kapsam yapmıyoruz; temel hedef okuma, dönüştürme ve rapor akışını kavramaktır.

Dosya kaynaklı hata durumları

Dosya işlemlerinde hata yalnızca Python sözdiziminden kaynaklanmaz:

  • Dosya bulunamıyor → FileNotFoundError,
  • Beklenen sütun yok → çoğu erişimde KeyError,
  • "puan" alanı sayı değil → ValueError,
  • Dosya boş,
  • Karakter kodlaması beklenenden farklı → UnicodeDecodeError gibi hatalar,
  • Yanlış delimiter nedeniyle beklenen sütunlar hiç oluşmamış olabilir.

13. haftada bu sözün karşılığını vereceğiz: FileNotFoundError, KeyError, ValueError gibi istisnaları try/except ile ele alacak ve hata mesajını nasıl okuyacağımızı göreceğiz.

Üret — CSV satış özeti

Fonksiyon DictReader kullanmalı, tutar alanını float değerine dönüştürmeli, toplam satış tutarı ile 100 TL ve üzeri kayıt sayısını (toplam, yuksek_satis_sayisi) olarak döndürmelidir. Beklenen sonuç (545.0, 2).

dosya = StringIO(veri), okuyucu = csv.DictReader(dosya) ve her kayıtta tutar = float(kayit["tutar"]) kullanabilirsiniz.

import csv
from io import StringIO

def csv_satis_ozeti(veri):
    dosya = StringIO(veri)
    okuyucu = csv.DictReader(dosya)

    toplam = 0
    yuksek_satis_sayisi = 0

    for kayit in okuyucu:
        tutar = float(kayit["tutar"])
        toplam = toplam + tutar

        if tutar >= 100:
            yuksek_satis_sayisi = yuksek_satis_sayisi + 1

    return toplam, yuksek_satis_sayisi

Gerçek ortam uygulaması

puanlar.txt ile şu programı kendi Python ortamınızda deneyin:

toplam = 0
adet = 0

with open("puanlar.txt", "r", encoding="utf-8") as dosya:
    for satir in dosya:
        puan = int(satir.strip())
        toplam = toplam + puan
        adet = adet + 1

print("Ortalama:", toplam / adet)

Daha sonra Excel veya başka bir tablo programından küçük bir CSV dışa aktarın. Dosyayı bir metin editöründe açıp şu üç soruya cevap verin:

  1. Sütun ayıracı ,; mi?
  2. Ondalık sayılar 12.5 mi 12,5 mi?
  3. utf-8 ile ilk sütun adı beklenmedik görünüyorsa utf-8-sig ile fark oluşuyor mu?

Bu inceleme, CSV’nin yalnızca “Excel dosyasının başka uzantısı” olmadığını; açık bir metin biçimi sözleşmesi olduğunu gösterir.

Bölüm özeti

  • with open(...) dosyayı güvenli biçimde açıp blok sonunda kapatır.
  • "r" okuma, "w" mevcut içeriği yeniden yazar, "a" dosyanın sonuna ekler.
  • read() tek string, readlines() string listesi üretir; doğrudan dosya üzerinde for satır satır dolaşır.
  • encoding="utf-8" metnin doğru çözümlenmesine yardım eder; BOM içeren UTF-8 CSV için utf-8-sig gerekebilir.
  • CSV ile newline="" kullanmak satır sonu işleme sorumluluğunu csv modülüne bırakır.
  • CSV sütun ayıracı her zaman virgül değildir; delimiter=";" gibi açıkça belirtilebilir.
  • Türkçe bölgesel ayarlı tablo uygulamalarından gelen CSV’lerde noktalı virgül ve ondalık virgül sık görülebilir.
  • Basit 12,512.5 dönüşümünde replace() kullanılabilir; karmaşık yerel sayı biçimleri için bu genel çözüm değildir.
  • csv.DictReader sütun adlarını anahtar olarak kullanır ve alanlar başlangıçta string gelir.
  • Dosya okuma, tür dönüştürme ve hesaplama adımlarını ayırmak kodu daha anlaşılır kılar.

Kendinizi kontrol edin

  1. "r", "w" ve "a" kipleri arasındaki fark nedir?
  2. read() ile readlines() hangi türde değerler döndürür?
  3. for karakter in dosya.read(): neden satırlar yerine karakterler üzerinde ilerler?
  4. newline="" CSV kullanımında ne işe yarar; delimiter ile farkı nedir?
  5. Türkçe Excel çıktısında ad;puan satırı tek sütun gibi okunuyorsa hangi DictReader ayarı kontrol edilmelidir?
  6. İlk sütun adı \ufeffad görünüyorsa hangi kodlama seçeneği yardımcı olabilir?
  7. float("12,5") neden hata verir ve basit ondalık virgül sözleşmesinde nasıl dönüştürülebilir?
  8. replace(",", ".") neden her yerel sayı biçimi için güvenli bir genel çözüm değildir?
  9. CSV’den gelen "78" değeri neden doğrudan sayısal puan olarak düşünülmemelidir?
  10. İnteraktif kitapta StringIO kullanmamızın nedeni nedir?

Bir sonraki bölümde dosya ve dönüşüm hataları dahil olmak üzere istisnaları, modülleri ve sistematik hata ayıklamayı ele alacağız.

Back to top