# Python'da JSON: dosya okuma ve yazma, CSV, pathlib ve UTF-8 kodlaması

URL: https://skillaria.top/tr/guides/python/python-json-dosya-islemleri

Python'da JSON için yerleşik json modülü kullanılır: json.load açık bir dosyadan veri okur, json.dump dosyaya yazar, json.loads ve json.dumps aynı işi metinlerle yapar. Dosyalar with open(yol, encoding="utf-8") ile açılır, yollar pathlib.Path ile kurulur, tablo verileri ise csv modülüyle okunur.

Python'da JSON ile çalışmak için ek bir kütüphane gerekmez: `json` modülü standart kütüphanenin parçasıdır ve sözlükleri, listeleri metne, metni de tekrar sözlük ve listeye çevirir. Yanında neredeyse her zaman üç şey daha gerekir: `with` ile birlikte kullanılan `open` fonksiyonu, yollar için `pathlib` modülü ve tablolar için `csv` modülü. Aşağıda hepsini çalışan kodlarla ve en sık yapılan hatalarla birlikte sırayla anlatıyoruz.

## Python open fonksiyonu: modlar ve kodlama

Her metin dosyası yerleşik `open(yol, mod, encoding=...)` fonksiyonuyla açılır. Bu fonksiyon `read`, `readline`, `write` metotlarına sahip bir dosya nesnesi döndürür ve nesne döngüyle satır satır dolaşılabilir.

| Mod | Ne yapar |
| --- | --- |

| `"r"` | Okuma (varsayılan). Dosya yoksa `FileNotFoundError` |

| `"w"` | Yazma. Dosya oluşturulur ya da **açılır açılmaz içeriği silinir** |

| `"a"` | Sona ekleme, mevcut içerik korunur |

| `"x"` | Yeni dosya oluşturma; dosya zaten varsa `FileExistsError` |

| `"b"` | Mod eki: bayt ile çalışma (`"rb"`, `"wb"`) |

### with neden gerekli

Dosyanın kapatılması gerekir: aksi halde veriler diske yazılmayabilir ve sistem dosya tanıtıcısını meşgul görür. `with` bloğu dosyayı otomatik kapatır; blok içinde hata olsa bile.

```
with open("notlar.txt", "w", encoding="utf-8") as f:
    f.write("İlk satır\n")
    f.write("İkinci satır\n")

with open("notlar.txt", encoding="utf-8") as f:
    for line in f:
        print(line.rstrip("\n"))
```

Dosyayı döngüyle okumak satırları teker teker işler; tüm dosyayı belleğe yüklemez. Bu yüzden gigabayt boyutundaki günlük dosyaları da bu şekilde işleyebilirsiniz. `f.read()` tüm içeriği tek bir metin olarak, `f.readlines()` ise satırların listesini verir.

### Metni dosyaya nasıl eklersiniz, eskisini silmeden

Yeni başlayanların en sık hatası, bir satır "eklemek" için dosyayı `"w"` modunda açmaktır. `"w"` dosyayı, daha ilk `write` çağrılmadan, açarken temizler. Sona eklemek için `"a"`, yanlışlıkla bir dosyanın üzerine yazmamak için `"x"` kullanın.

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

`write` satır sonu eklemez; `"\n"` açıkça yazılmalıdır. Alternatif olarak `print(..., file=f)` kullanabilirsiniz: satır sonunu o koyar.

## UTF-8 kodlaması: "bozuk karakterler" neden çıkar

Python 3.15'e kadar `open()`, `encoding` parametresi verilmezse sistemin kodlamasını kullanır. Linux ve macOS'ta bu UTF-8'dir, Türkçe Windows'ta ise genellikle cp1254 ya da cp1251 gibi eski bir kodlama. Sunucuda sorunsuz çalışan bir betik, bir arkadaşın bilgisayarında "Ã‡" gibi bozuk metin üretebilir ya da `UnicodeDecodeError` ile çökebilir.

Python 3.15'te PEP 686 gereği UTF-8 modu varsayılan olarak açıktır: `encoding` verilmeyen `open()` tüm işletim sistemlerinde UTF-8 okur ve yazar. Eski davranışı ortam değişkeni `PYTHONUTF8=0` ya da `-X utf8=0` bayrağıyla geri alabilirsiniz; sistem kodlamasını açıkça istemek için `encoding="locale"` kullanılır.

```
import sys
print(sys.flags.utf8_mode)   # Python 3.15'te 1

open("eski.txt", encoding="locale")       # sistem kodlaması
open("eski_excel.csv", encoding="cp1254") # cp1254 ile kaydedilmiş dosya
```

Ters yönde de bir risk var: Excel'den ya da Windows betiğinden gelen eski bir cp1254 CSV'si artık UTF-8 olarak okunur ve `UnicodeDecodeError` verir. Çözüm, dosyayı önce doğru kodlamayla okuyup UTF-8 olarak yeniden kaydetmektir. Kural değişmiyor: `encoding` parametresini her zaman açıkça yazın; kod her sürümde aynı davranır.

## pathlib: yollar nesne olarak

Yolları metin birleştirmeyle (`"veri" + "/" + ad`) kurmak zahmetlidir ve işletim sistemleri arasında bozulur. `pathlib` modülündeki `Path` sınıfında yollar `/` operatörüyle birleşir ve nesnenin kullanışlı özellikleri vardır.

```
from pathlib import Path

veri = Path("veri")
csv_yolu = veri / "harcamalar.csv"

print(csv_yolu.name)    # harcamalar.csv
print(csv_yolu.stem)    # harcamalar
print(csv_yolu.suffix)  # .csv
print(csv_yolu.parent)  # veri
print(csv_yolu.exists())

veri.mkdir(parents=True, exist_ok=True)
(veri / "merhaba.txt").write_text("Merhaba", encoding="utf-8")
print((veri / "merhaba.txt").read_text(encoding="utf-8"))

for p in veri.glob("*.csv"):
    print(p)
```

`read_text` ve `write_text`, küçük dosyalar için `open` + `with` ikilisinin yerini alır. `Path` nesnesini `open`, `json` ve `csv` gibi tüm bu araçlara doğrudan verebilirsiniz. Yolu komutun çalıştığı klasöre değil, betiğin kendi klasörüne göre kurmak için: `Path(__file__).parent / "veri"`.

Python 3.14'te `Path` nesnesine `copy()` ve `move()` metotları eklendi; basit kopyalama için artık `shutil` gerekmez. Aynı sürümde standart kütüphaneye Zstandard sıkıştırması için `compression.zstd` modülü geldi (PEP 784).

## Python'da JSON: load, dump, loads, dumps

JSON, veri alışverişi için kullanılan metin tabanlı bir biçimdir: API'ler bu biçimde yanıt verir, yapılandırmalar ve raporlar bu biçimde saklanır. `json` modülü iki işlemi yapar: serileştirme (Python nesnesi → JSON metni) ve seri durumdan çıkarma (metin → nesne). Dört fonksiyon vardır ve aralarındaki karışıklık sık sorulan bir sorudur.

| Fonksiyon | Ne yapar |
| --- | --- |

| `json.dumps(obj)` | Nesne → JSON metni |

| `json.loads(s)` | JSON metni → nesne |

| `json.dump(obj, f)` | Nesneyi açık bir dosyaya yazar |

| `json.load(f)` | Açık bir dosyadan JSON okur |

Akılda tutmak kolay: sondaki `s`, string (metin) ile çalışmak demektir; yoksa dosya ile çalışılır.

### Tür eşleşmeleri

| Python | JSON |
| --- | --- |

| `dict` | nesne `{}` |

| `list`, `tuple` | dizi `[]` |

| `str` | metin |

| `int`, `float` | sayı |

| `True` / `False` | `true` / `false` |

| `None` | `null` |

Demet geri okunduğunda liste olur. Kümeler, tarihler ve `Decimal` ise modül tarafından tanınmaz; `TypeError: Object of type ... is not JSON serializable` hatası alırsınız.

### JSON dosyasını nasıl kaydedersiniz

```
import json
from pathlib import Path

rapor = {
    "ay": "2026-10",
    "toplam": 15230.5,
    "kategoriler": {"yiyecek": 8200, "ulaşım": 2100},
    "etiketler": ["ev", "iş"],
}

yol = Path("veri/rapor.json")
yol.parent.mkdir(parents=True, exist_ok=True)
with yol.open("w", encoding="utf-8") as f:
    json.dump(rapor, f, ensure_ascii=False, indent=2)
```

`ensure_ascii=False` Türkçe karakterleri olduğu gibi yazar. Bu parametre olmazsa dosyada "yiyecek" yerine `"y..."` gibi kaçış dizileri görünür; bu geçerli bir JSON'dır ama insanın okuması zordur. `indent=2` girintili biçimlendirme sağlar.

### JSON dosyasını nasıl okursunuz

```
with open("veri/rapor.json", encoding="utf-8") as f:
    veri = json.load(f)

print(veri["toplam"])                   # 15230.5
print(veri["kategoriler"]["yiyecek"])   # 8200
```

Sonuç olağan bir sözlük ya da listedir ve onunla alışılmış araçlarla çalışılır. Dosya JSON değilse ya da yarım kalmışsa, satır ve konum bilgisiyle `json.JSONDecodeError` fırlatılır. Veri dışarıdan geliyorsa bu hatayı yakalamanız gerekir.

### JSON metnini ayrıştırmak ve güzel yazdırmak

```
import json

ham = '{"ad": "Ayşe", "beceriler": ["python", "sql"], "aktif": true}'
kullanici = json.loads(ham)
print(kullanici["beceriler"][0])   # python

print(json.dumps(kullanici, ensure_ascii=False, indent=2, sort_keys=True))
```

`sort_keys=True` çıktıdaki anahtarları sıralar; böylece dosyaları git'te karşılaştırmak kolaylaşır. Terminalden bir JSON dosyasını hızlıca biçimlendirmek için yerleşik araç da vardır: `python -m json.tool veri/rapor.json`.

HTTP API'lerinin yanıtları da JSON metnidir. `requests` kütüphanesi bunu `response.json()` ile ayrıştırır; altta yatan işlem yine `json.loads`'tur.

### Tuzak: JSON anahtarları her zaman metindir

```
d = {1: "ocak", 2: "şubat"}
geri = json.loads(json.dumps(d))
print(geri == d)   # False
print(geri)        # {'1': 'ocak', '2': 'şubat'}
# geri[1] -> KeyError, geri["1"] yazmalısınız

duzeltilmis = {int(k): v for k, v in geri.items()}
```

JSON'da nesne anahtarları yalnızca metin olabilir; bu yüzden sayısal anahtarlar serileştirme sonrasında metne dönüşür. Okurken bunları yeniden sayıya çevirin.

### Kendi türleriniz: tarihler ve Decimal

```
import json
from datetime import date

def varsayilan(obj):
    if isinstance(obj, date):
        return obj.isoformat()
    raise TypeError(f"{type(obj).__name__} türü serileştirilemiyor")

print(json.dumps({"gun": date(2026, 10, 1)}, default=varsayilan))
# {"gun": "2026-10-01"}
```

`default` parametresindeki fonksiyon, tanınmayan her nesne için çağrılır. Daha karmaşık durumlarda `json.JSONEncoder` sınıfından türetip `default` metodunu yeniden yazabilirsiniz.

### JSON dizisine nasıl eleman eklersiniz

JSON, metin günlükleri gibi sona eklenemez: dosyayı okuyup değiştirmeniz ve tamamını yeniden yazmanız gerekir.

```
yol = Path("veri/kayitlar.json")
kayitlar = json.loads(yol.read_text(encoding="utf-8")) if yol.exists() else []
kayitlar.append({"id": len(kayitlar) + 1, "baslik": "yeni"})
yol.write_text(json.dumps(kayitlar, ensure_ascii=False, indent=2), encoding="utf-8")
```

Kayıtlar sürekli ve çok sayıda ekleniyorsa JSON Lines biçimi daha uygundur: her satırda bir JSON nesnesi bulunur ve dosya `"a"` modunda açılır.

## Python'da CSV: csv modülü

CSV, satırların kayıt, değerlerin virgülle ayrıldığı metin tablosudur. `csv` modülü tırnakları, değerlerin içindeki virgülleri ve satır sonlarını doğru işler; elle yazılmış `split(",")` bunları yapamaz.

```
import csv

with open("veri/harcamalar.csv", newline="", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    toplam = 0.0
    for row in reader:
        toplam += float(row["tutar"])
        print(row["tarih"], row["kategori"], row["tutar"])
print("Toplam:", toplam)
```

`csv.DictReader` her satırı, dosyanın başlık satırına göre bir sözlüğe çevirir. Tüm değerler metin olarak gelir; sayıları ve tarihleri kendiniz çevirin (`float`, `int`, `date.fromisoformat`). Türkçe Excel'in kaydettiği, ayırıcısı noktalı virgül (`;`) olan dosyaları `delimiter=";"` parametresiyle okursunuz.

```
satirlar = [
    {"tarih": "2026-10-01", "kategori": "yiyecek", "tutar": 450},
    {"tarih": "2026-10-02", "kategori": "ulaşım", "tutar": 60},
]
with open("veri/cikti.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["tarih", "kategori", "tutar"])
    writer.writeheader()
    writer.writerows(satirlar)
```

Yazarken `newline=""` zorunludur: yoksa Windows'ta satırlar arasında boş satırlar belirir. Dosya Excel'de açılacaksa `encoding="utf-8-sig"` kullanın; başındaki BOM işareti Excel'in UTF-8'i tanımasını sağlar.

## CSV'den JSON'a: tam örnek

```
import csv
import json
from collections import defaultdict
from pathlib import Path

kaynak = Path("veri/harcamalar.csv")
hedef = Path("veri/rapor.json")

kategori_toplam = defaultdict(float)
with kaynak.open(newline="", encoding="utf-8") as f:
    for row in csv.DictReader(f):
        kategori_toplam[row["kategori"]] += float(row["tutar"])

rapor = {"toplam": sum(kategori_toplam.values()), "kategoriler": dict(kategori_toplam)}
hedef.write_text(json.dumps(rapor, ensure_ascii=False, indent=2), encoding="utf-8")
print(hedef.read_text(encoding="utf-8"))
```

Her rapor betiğinin çekirdeği budur: CSV'den girdi okunur, bir sözlükte toplanır ve JSON olarak çıktı verilir.

## Tipik hatalar

- `FileNotFoundError` — yol göreli ve komutun çalıştığı klasöre göre hesaplanıyor, betiğin klasörüne göre değil. `Path(__file__).parent` kullanın.
- Dosya boşaldı — `"w"` yerine `"a"` açılması gerekirken `"w"` açıldı.
- `UnicodeDecodeError` — dosya farklı bir kodlamada; kodlamayı açıkça belirtin (`cp1254`, `utf-8-sig`).
- `TypeError: Object of type set is not JSON serializable` — listeye çevirin ya da `default` fonksiyonu verin.
- JSON yüklendikten sonra `KeyError` — sayısal anahtarlar metne dönüşmüş.
- Kendi dosyanız `json.py` ya da `csv.py` adını taşıyor — standart modülü gölgeler ve `import json` sizin dosyanızı içe aktarır.

## Özet

Python'da JSON için standart kütüphane yeterlidir: dosyalar için `json.load` ve `json.dump`, metinler için `loads` ve `dumps`; okunabilir çıktı için `ensure_ascii=False` ve `indent`. Dosyaları kodlamayı belirterek `with` ile açın, yolları `pathlib` ile kurun, tabloları `csv.DictReader` ile okuyun. Kursta bu konu uygulamalı işlenir: harcama takipçisi CSV'den harcamaları okur ve raporu JSON olarak kaydeder.

## FAQ

**json.load ile json.loads arasındaki fark nedir?**

json.load açık bir dosya nesnesinden okur, json.loads ise metni ayrıştırır. Benzer biçimde json.dump dosyaya yazar, json.dumps ise metin döndürür.

**Türkçe karakterleri JSON'da \u kaçış dizileri olmadan nasıl kaydederim?**

json.dump ya da json.dumps içinde ensure_ascii=False verin ve dosyayı encoding="utf-8" ile açın.

**JSON ile çalışmak için kütüphane kurmam gerekir mi?**

Hayır, json modülü standart kütüphanenin parçasıdır; import json yazmak yeterlidir.

**JSON'a tarih ya da küme kaydedebilir miyim?**

Doğrudan olmaz: tarihi isoformat ile metne, kümeyi listeye çevirin ya da default parametresine bir fonksiyon verin.

**Belleğe sığmayan büyük bir JSON dosyasını nasıl okurum?**

json.load dosyanın tamamını okur. Büyük veri için JSON Lines biçimini kullanın ve her satırı json.loads ile ayrı ayrı işleyin.


---
Source: Skillaria.Top (https://skillaria.top)
