Anasayfa / C# / CONSOLE APPS / C# Dosya İşlemleri (File I/O)

C# Dosya İşlemleri (File I/O)

C# programlama dili eğitim serimizde şimdiye kadar değişkenleri, döngüleri, nesne yönelimli programlamayı ve hata yakalama (try-catch) mekanizmalarını öğrendik. Ancak şu ana kadar yazdığımız programlardaki tüm veriler bilgisayarın “geçici hafızasında” (RAM) tutuluyordu. Yani programı kapattığınız anda kullanıcı adları, hesaplanan puanlar veya listeler sonsuza dek siliniyordu.

Gerçek dünyadaki yazılımların verileri kalıcı olarak saklaması gerekir. Bir oyunun kullanıcının rekor skorunu kaydetmesi, bir e-ticaret sitesinin sipariş detaylarını loglaması veya bir ayar dosyasını okuması buna örnektir. İşte C# dilinde verileri kalıcı hale getirmenin en temel yolu Dosya İşlemleri (File I/O) yapmaktır.

Bu kapsamlı rehberimizde, C# kullanarak metin (txt) dosyaları oluşturmayı, bu dosyalara veri yazmayı, okumayı ve profesyonel yazılım geliştirme süreçlerinde büyük dosyaların performanslı bir şekilde nasıl yönetileceğini öğreneceğiz.


1. Dosya İşlemlerinin Kalbi: System.IO Kütüphanesi

C# dilinde dosya, klasör (dizin) ve yol (path) işlemleri yapmak için .NET’in sunduğu System.IO (Input/Output – Girdi/Çıktı) isim uzayını (namespace) kullanırız. Bu kütüphane; dosyaları oluşturmak, okumak, taşımak ve silmek için ihtiyacımız olan tüm sınıfları (File, Directory, Path, StreamReader vb.) içinde barındırır.

Dosya işlemlerine başlamadan önce kod dosyanızın en üstüne bu kütüphaneyi eklemelisiniz (Top-level statements kullanıyorsanız dosyanın herhangi bir yerine eklemeden de .NET’in global using özelliği sayesinde doğrudan kullanabilirsiniz, ancak geleneksel yöntemde şu şekilde eklenir):

using System.IO;


2. Dosyaya Veri Yazma (File.WriteAllText ve File.AppendAllText)

En temel işlem, bilgisayarımızın diskinde bir dosya oluşturmak ve içine metin yazmaktır. Bunun için File sınıfının pratik metotlarını kullanırız.

Dosya Oluşturma ve Üzerine Yazma (WriteAllText): Bu metot, belirttiğiniz isimde bir dosya yoksa onu oluşturur; eğer dosya zaten varsa içindeki eski verileri tamamen siler ve yeni veriyi yazar.

// "notlar.txt" adında bir dosya oluşturulur ve içine metin yazılır.
string dosyaYolu = "notlar.txt";
string yazilacakMetin = "C# dosya işlemlerini öğrenmek harika!";

File.WriteAllText(dosyaYolu, yazilacakMetin);

Console.WriteLine("Dosya başarıyla oluşturuldu ve metin yazıldı.");

(Not: Dosya yolunu sadece “notlar.txt” olarak verirseniz, dosya doğrudan projenizin çalıştığı klasörün (genellikle bin/Debug/net8.0 gibi) içine kaydedilir. İsterseniz “C:\Klasorum\notlar.txt” gibi tam bir yol da belirtebilirsiniz.)

Dosyanın Sonuna Ekleme Yapma (AppendAllText): Özellikle “Log” (kayıt) dosyaları tutarken eski verilerin silinmesini istemeyiz. Sadece dosyanın en sonuna yeni bir satır eklemek isteriz. Bunun için “Append” (ekle) komutu kullanılır.

string logYolu = "sistem_loglari.txt";
string yeniLog = "\nSisteme yeni bir kullanıcı giriş yaptı. Tarih: " + DateTime.Now;

// Dosya yoksa oluşturur, varsa içindekileri silmeden sonuna ekler.
File.AppendAllText(logYolu, yeniLog);


3. Dosyadan Veri Okuma (File.ReadAllText ve File.ReadAllLines)

Kayıtlı bir dosyayı okumak, yazmak kadar basittir. İhtiyacınıza göre dosyayı tek bir bütün metin olarak veya satır satır okuyabilirsiniz.

Tüm Dosyayı Tek Seferde Okumak (ReadAllText):

string okunanMetin = File.ReadAllText("notlar.txt");
Console.WriteLine("Dosyanın İçeriği:");
Console.WriteLine(okunanMetin);

Dosyayı Satır Satır Diziye Aktarmak (ReadAllLines): Dosyanızda 100 farklı isim alt alta yazılıysa, bunu bir döngüyle okumak için bir diziye (array) aktarmak çok kullanışlıdır.

// Dosyadaki her bir satır, string dizisinin bir elemanı olur.
string[] ogrenciler = File.ReadAllLines("ogrenci_listesi.txt");

Console.WriteLine("Öğrenci Listesi:");
foreach (string ogrenci in ogrenciler)
{
    Console.WriteLine($"- {ogrenci}");
}


4. Profesyonel Yaklaşım: Akışlar (Streams) ile Çalışmak

File.ReadAllText metodu küçük boyutlu dosyalar için kusursuzdur. Ancak 5 GB boyutunda bir log dosyanız olduğunu düşünün! Bu dosyayı ReadAllText ile tek seferde okumaya çalışırsanız, bilgisayarınızın RAM’i dolacak ve uygulamanız çökecektir.

İşte profesyonel .NET geliştiricileri, büyük boyutlu dosya ve akış I/O (File and Stream I/O) işlemleri için her zaman StreamReader ve StreamWriter sınıflarını kullanır. Bu sınıflar dosyayı tek seferde yutmak yerine, bir pipetle su çeker gibi yavaş yavaş (satır satır) hafızaya alırlar.

Önceki “Yapıcı ve Yıkıcı Metotlar” dersinde öğrendiğimiz IDisposable arayüzü sayesinde, açık kalan dosya bağlantılarını using bloğu ile anında kapatmalıyız.

StreamReader ile Dosya Okuma Örneği: Örneğin, File.OpenText(String) metodu, metin dosyasını okumak üzere bir StreamReader nesnesi döndürür.

string devDosyaYolu = "buyuk_veriler.txt";

// using bloğu işimiz bittiğinde dosyayı RAM'den güvenle temizler (Dispose eder)
using (StreamReader okuyucu = File.OpenText(devDosyaYolu))
{
    string satir;
    int satirSayaci = 0;

    // ReadLine() metodu dosyanın sonuna gelince null döndürür.
    // null olmadığı sürece (!= null) döngü çalışmaya devam eder.
    while ((satir = okuyucu.ReadLine()) != null)
    {
        satirSayaci++;
        // Gerekirse sadece belirli satırları işleyebiliriz, böylece RAM'i koruruz
        Console.WriteLine($"{satirSayaci}. Satır: {satir}");
    }
}

Özellikle C# içerisindeki yield return yapısıyla iterator (yineleyici) metotlar yazarak, dosyadaki satırları devasa bir diziye atamadan, ihtiyaç duyuldukça tembel (lazy) bir şekilde okunmasını sağlayabilirsiniz.

StreamWriter ile Performanslı Yazma:

using (StreamWriter yazici = new StreamWriter("performansli_yazilar.txt", true))
{
    // 'true' parametresi dosyanın sonuna ekleme (append) yapılacağını belirtir.
    yazici.WriteLine("Bu satır StreamWriter ile güvenli bir akışta yazıldı.");
}


5. Klasör (Directory) ve Güvenlik İşlemleri

C# ile sadece dosyaları değil, bilgisayardaki klasörleri de yönetebilirsiniz. System.IO altındaki Directory sınıfı bu işe yarar. Dosya işlemi yapmadan önce dosyanın veya klasörün gerçekten var olup olmadığını kontrol etmek hayat kurtarır, aksi takdirde programımız FileNotFoundException hatası verebilir.

Bir önceki eğitimimizdeki Hata Yakalama (Try-Catch) mimarisini dosya işlemleriyle birleştirelim:

string klasorYolu = "Yedekler";
string hedefDosya = "Yedekler\\ayarlar.txt";

try
{
    // 1. Klasör var mı diye kontrol edelim. Yoksa oluşturalım.
    if (!Directory.Exists(klasorYolu))
    {
        Directory.CreateDirectory(klasorYolu);
        Console.WriteLine("Yedekler klasörü başarıyla oluşturuldu.");
    }

    // 2. Dosya okumadan önce varlığını kontrol edelim
    if (File.Exists(hedefDosya))
    {
        string icerik = File.ReadAllText(hedefDosya);
        Console.WriteLine($"Okunan Ayar: {icerik}");
    }
    else
    {
        Console.WriteLine("Dosya bulunamadı! Yeni, boş bir ayar dosyası oluşturuluyor...");
        File.WriteAllText(hedefDosya, "Varsayılan Ayarlar Yüklendi.");
    }
}
catch (UnauthorizedAccessException)
{
    // Klasöre yazma yetkimiz yoksa bu hatayı yakalarız
    Console.WriteLine("Hata: Bu klasöre yazma izniniz bulunmuyor (Yönetici yetkisi gerekli).");
}
catch (Exception ex)
{
    // Beklenmeyen diğer tüm I/O (Girdi/Çıktı) hataları için
    Console.WriteLine($"Sistem Hatası: {ex.Message}");
}


Sonuç ve Neler Öğrendik?

Tebrikler! C# kullanarak işletim sistemiyle etkileşime geçmeyi ve Dosya İşlemlerini (File I/O) detaylıca öğrendiniz. C#’ın kalbi sayılan System.IO kütüphanesi ile küçük notları File sınıfıyla yönetirken, büyük dosyalar için StreamReader / StreamWriter gibi performans dostu yaklaşımlara başvurduk. Aynı zamanda dosya varlıklarını Exists metotlarıyla kontrol ederek programımızın dış dünyadaki sürprizlere (silinen dosyalar, yetki hataları) karşı çökmesini engellemeyi (try-catch) pratik ettik.

Bu özellikler, gelecekte yazacağınız masaüstü uygulamalarında (log tutmak için) veya bir backend Web API projesinde (.json konfigürasyonlarını okurken) doğrudan kullanacağınız altın değerindeki yeteneklerdir. Bol pratik yaparak bu bilgileri kendi C# projelerinizde hayata geçirebilirsiniz. İyi kodlamalar!

Etiketlendi:

Cevap bırakın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir