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 bölümün kapsamı
with open(...)kullanımı ve"r","w","a"kipleriread(),readlines()ve dosya üzerindeforfarkı- kodlama seçeneğinin etkisi ve BOM sorunu
- CSV’de
delimitervenewline=""seçeneklerinin görevi csv.DictReaderalanlarının metin gelmesi ve dönüştürülmesi- ondalık virgül sorunu ve
replace()çözümünün sınırı - okuma, dönüştürme ve hesaplama adımlarının ayrılması
csv.writerile yazma seçeneklerinin ayrıntısıpathlibile yol işlemleri- ikili (binary) dosya kipleri
Bu başlıklar konunun devamıdır; ileride karşınıza çıkar ama bu derste ezberlemeniz beklenmiyor.
Excel’den gelen CSV neden tek sütun görünüyor?
Dosyadaki veri her zaman beklediğiniz biçimde olmaz: ayraç noktalı virgül olabilir, dosyanın başında görünmez bir işaret bulunabilir, ondalık ayraç virgül olabilir. Üçü ayrı sorundur ve ayrı ayrı çözülür.
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 dosyaaçılan dosya nesnesine verdiğimiz addır.
with bloğu bittiğinde dosya otomatik olarak kapatılır.
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.
"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)) # strread() 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)) # listHer 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.
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.
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)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.
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
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ı →
UnicodeDecodeErrorgibi hatalar, - Yanlış
delimiternedeniyle 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_sayisiGerç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:
- Sütun ayıracı
,mı;mi? - Ondalık sayılar
12.5mi12,5mi? utf-8ile ilk sütun adı beklenmedik görünüyorsautf-8-sigile 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.
Tek sayfa özet
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 üzerindeforsatır satır dolaşır.encoding="utf-8"metnin doğru çözümlenmesine yardım eder; BOM içeren UTF-8 CSV içinutf-8-siggerekebilir.- CSV ile
newline=""kullanmak satır sonu işleme sorumluluğunucsvmodü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,5→12.5dönüşümündereplace()kullanılabilir; karmaşık yerel sayı biçimleri için bu genel çözüm değildir. csv.DictReadersü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.
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.
Bu bölümün kazanımları
Bu bölümü bitiren öğrenci:
with open(...)ile dosyayı güvenli açar ve"r","w","a"kiplerini ayırır.read(),readlines()ve dosya üzerindefordavranışlarını ayırır.- Kodlama seçeneğinin metni nasıl etkilediğini bilir ve BOM sorununu tanır.
- CSV’de
delimitervenewline=""seçeneklerinin görevini açıklar. csv.DictReaderalanlarının metin geldiğini bilir ve dönüştürür.- Ondalık virgül sorununu ele alır ve
replace()çözümünün sınırını bilir. - Okuma, dönüştürme ve hesaplama adımlarını birbirinden ayırır.