C#'ta System.IO.FileNotFoundException hatası, kodda verdiğin dosya yolunun programın çalıştığı yerde bir dosyaya karşılık gelmediği anlamına gelir. Çözmek için üç şeye bakarsın: istisna mesajındaki gerçek yola, göreli yolun hangi çalışma klasörüne göre hesaplandığına ve dosyanın derlenmiş çıktı klasörüne kopyalanıp kopyalanmadığına. Dosya projenin içinde, kod dosyanın hemen yanında durabilir; program yine de başka bir klasörde arıyor olabilir.
Hata mesajı sana neyi söylüyor ve nereden başlamalısın?
Mesaj genellikle Could not find file ifadesiyle başlar ve tek tırnak içinde bir yol gösterir. Mesajın dili .NET'in ve işletim sisteminin dil ayarına göre değişebilir; Türkçe bir ortamda karşına Türkçe bir ifade çıkabilir. Yol kısmı ise değişmez ve en değerli ipucudur.
Kodda "notlar.txt" gibi kısa bir ad yazmış olsan bile mesajda çoğu zaman tam yol görürsün. Bu yol, .NET'in dosyayı gerçekte aradığı yerdir. Aradığın klasör ile mesajdaki klasör aynı değilse sorunun kaynağını bulmuşsundur. İstisna nesnesinin FileName özelliği de bulunamayan dosyanın adını taşır; catch bloğunda bunu yazdırarak hangi dosyanın sorun çıkardığını görebilirsin.
Hızlı teşhis için şu sırayı izle:
- Mesajdaki yolu oku. Dosya adını ve klasörü, kodda yazdığınla karşılaştır. Ayrıntısı bu bölümde.
- Yolun göreli mi mutlak mı olduğuna bak. Sürücü ya da kökten başlamayan yol göreli yoldur. Ayrıntısı hemen sonraki bölümde.
- Çalışma dizinini yazdır. Göreli yolun hangi klasöre göre hesaplandığını tahmin etme, programa söylet. Ayrıntısı "Körlemesine File.Exists yerine" bölümünde.
- Dosyanın çıktı klasöründe olup olmadığına bak. Dosya projede görünse de derlenmiş çıktıya kopyalanmamış olabilir. Ayrıntısı Visual Studio bölümünde.
- Dosya adını, büyük küçük harfi ve uzantıyı kontrol et. Gizli uzantılar yüzünden
notlar.txtaslındanotlar.txt.txtolabilir. Ayrıntısı "Dosya adı tuzakları" bölümünde.
Göreli ve mutlak yol farkı: dosya neden 'yanında durduğu halde' bulunamıyor?

Mutlak yol, sürücü harfinden ya da kök dizinden başlar ve dosyayı tek başına tarif eder. Göreli yol ise yalnızca notlar.txt ya da veri/notlar.txt gibi bir ifadedir; hangi klasörden başlayacağı yolun kendisinde yazmaz. Burada kritik bilgi şudur:
Göreli dosya yolu, kod dosyasına göre değil uygulamanın çalışma dizinine göre değerlendirilir.
Yani .cs dosyasının durduğu klasör hesaba katılmaz. Kod dosyasının yanına bir metin dosyası koymak, programın onu bulacağı anlamına gelmez. Program zaten kaynak koddan değil, derlenmiş çıktıdan çalışır.
İki farklı klasör: çalışma dizini ve uygulamanın klasörü
Directory.GetCurrentDirectory() sürecin çalışma dizinini verir. Göreli yollar bu klasöre göre çözülür. Programı hangi araçtan ve hangi klasörden başlattığına göre bu değer değişebilir; bu yüzden tahmin yürütmek yerine kendin yazdırıp görmen en güvenlisidir.
AppContext.BaseDirectory ise uygulamanın çalıştığı derlenmiş çıktının bulunduğu klasörü verir. Dosyayı projeyle birlikte dağıtıp çıktı klasöründen okumak istiyorsan yolu bu klasörden başlatman daha tutarlı olur. Çalışma dizini başka bir yere kayarsa bu yol etkilenmez.
Yolu elle birleştirme, Path.Combine kullan
Klasör ile dosya adını + ve ters bölüyle birleştirmek, ayırıcıyı unutmaya ya da iki kez yazmaya açık bir yöntemdir. Ayırıcı karakter işletim sistemine göre de değişir. Path.Combine parçaları sistemin kullandığı ayırıcıyla birleştirir. Tek dikkat edeceğin nokta şu: sonraki parçalardan biri kökten başlayan bir yolsa, öncekiler yok sayılır. Bu yüzden ikinci parçaya "/notlar.txt" gibi bir ifade yazma.
Mantık şöyle kurulur: Path.Combine(AppContext.BaseDirectory, "notlar.txt") uygulamanın klasörünü başlangıç alır ve dosya adını güvenli biçimde ekler. Bu yolu çalışırken görüp File.Exists ile doğrulamak ise bir sonraki bölümün konusu.
Körlemesine File.Exists yerine: önce tam yolu yazdır, sonra doğrula
Dosyanın neden bulunamadığını tahmin etmek yerine programın aradığı yolu ekrana yazdır. Aşağıdaki örnek iki aday tam yol kurar: birincisi çalışma klasörüne, ikincisi uygulamanın çalıştığı çıktı klasörüne göre hesaplanır. Sonra her yol için File.Exists sonucunu gösterir.
using System;
using System.IO;
class Program
{
static void Main()
{
string dosyaAdi = "notlar.txt";
string[] adaylar =
{
Path.Combine(Directory.GetCurrentDirectory(), dosyaAdi),
Path.Combine(AppContext.BaseDirectory, dosyaAdi)
};
foreach (string yol in adaylar)
{
Console.WriteLine("Aday yol: " + yol);
bool varMi = File.Exists(yol);
Console.WriteLine("File.Exists: " + varMi);
if (varMi)
{
Console.WriteLine(File.ReadAllText(yol));
}
}
try
{
File.ReadAllText(adaylar[0]);
}
catch (FileNotFoundException e)
{
Console.WriteLine("Aranan dosya: " + e.FileName);
}
}
}
Dosya çıktı klasörüne kopyalanmamışsa çıktı şuna benzer:
Aday yol: <proje-klasoru>/bin/<yapilandirma>/<hedef-cati>/notlar.txt
File.Exists: False
Aday yol: <proje-klasoru>/bin/<yapilandirma>/<hedef-cati>/notlar.txt
File.Exists: False
Aranan dosya: <proje-klasoru>/bin/<yapilandirma>/<hedef-cati>/notlar.txt
Dosya o klasöre kopyalandığında iki satırda da File.Exists: True görürsün ve dosyanın içeriği yazdırılır. Programı farklı bir çalışma klasöründen başlatırsan birinci yol değişebilir; ikisini birlikte yazdırmanın amacı bu farkı görmendir.
File.Exists yol geçersizse ya da erişim izni yoksa da istisna fırlatmadan false döndürür. Bu yüzden False sonucu "dosya yok" demek değil, "bu yolda erişilebilir bir dosya bulunamadı" demektir. Yazdırdığın yolu Dosya Gezgini'nde açarak kontrol et.
catch bloğu sorunu çözmez, yalnızca bilgi toplar. e.FileName aranan dosyanın adını ya da yolunu verir; hatayı susturmak için kullanma. Dosya işlemleri ve istisnalar konusunda seviyeni görmek istersen ücretsiz C# bilgi testini çözebilirsin.
Visual Studio'da dosya neden çıktı klasörüne gelmiyor?

Çıktı klasörü, derlenen uygulamanın konduğu bin altındaki <yapilandirma>/<hedef-cati> klasörüdür; örneğin bin/Debug/<hedef-cati>. Program buradan çalışır. Proje klasörüne eklediğin bir metin dosyası ise kendiliğinden bu klasöre kopyalanmaz, bu yüzden kodun aradığı yerde bulunmaz.
Çözüm için şu adımları izle:
- Solution Explorer'da dosyaya tıkla.
- Properties penceresinde Copy to Output Directory ayarını bul.
- Değeri Copy always ya da Copy if newer olarak değiştir.
- Projeyi yeniden derle ve dosyanın çıktı klasöründe göründüğünü Dosya Gezgini'nden doğrula.
Seçeneklerin anlamı şöyledir: Do not copy dosyayı kopyalamaz, Copy always her derlemede kopyalar, Copy if newer yalnızca kaynak dosya daha yeniyse kopyalar. Aynı ayar .csproj dosyasında şöyle görünür:
<ItemGroup>
<None Update="notlar.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
Burada PreserveNewest "Copy if newer" seçeneğine, Always "Copy always" seçeneğine karşılık gelir. Kopyalama yapılmasını istemiyorsan öğeyi hiç eklemeyebilir ya da değeri Never yapabilirsin.
Kopyalamanın çalıştığını Dosya Gezgini'nde bin altındaki klasörü açıp dosyayı görerek kontrol et. Önceki bölümdeki örneği tekrar çalıştırdığında File.Exists sonucu True oluyorsa sorun çözülmüştür.
Dosya adı tuzakları: büyük küçük harf, uzantı ve gizli uzantı
Yol doğru klasörü gösteriyor olsa bile ad birebir tutmuyorsa dosya bulunamaz. Kodda yazdığın ad ile diskteki ad harfi harfine aynı olmalıdır. veri.txt yerine veriler.txt, ogrenci.txt yerine öğrenci.txt yazmak, addaki bir boşluğu atlamak ya da uzantıyı hiç yazmamak aynı istisnayı üretir.
Büyük küçük harf konusunda dosya sistemi belirleyicidir. Bazı sistemlerde Veri.txt ile veri.txt aynı dosya sayılır, bazılarında iki ayrı dosyadır. Kodu başka bir bilgisayara ya da işletim sistemine taşıdığında sürpriz yaşamamak için kodda ve diskte aynı yazımı kullan. Türkçe karakterlerde de aynı disiplin geçerlidir: ı ile i farklı harflerdir.
Gizli uzantı tuzağı
Windows'ta bilinen dosya uzantıları gizliyse Dosya Gezgini'nde metin.txt görünen bir dosyanın gerçek adı metin.txt.txt olabilir. Not Defteri'nde "Farklı kaydet" ile adı metin.txt yazıp kaydettiğinde bu sık yaşanır. Dosya Gezgini'nin görünüm ayarlarından dosya adı uzantılarını görünür yap; böylece gerçek adı olduğu gibi görürsün.
Gözle kontrol etmek yerine kodun gördüğü adı da yazdırabilirsin:
string klasor = AppContext.BaseDirectory;
foreach (string yol in Directory.GetFiles(klasor, "*.txt"))
{
Console.WriteLine(Path.GetFileName(yol));
}
Dosya gizli uzantı yüzünden yanlış adlandırılmışsa çıktı şöyle olur:
metin.txt.txt
Kodda metin.txt aradığın için bulunamaz. Dosyayı yeniden adlandır ya da kodu gerçek adla eşleştir.
Kısa kontrol listesi: adı kopyalayıp koda yapıştır, uzantıyı yaz, boşluk ve Türkçe karakterleri gözden geçir, uzantıları görünür yap ve çıktı klasöründeki adı yukarıdaki gibi koddan listeleyip karşılaştır.
Sınır durumu: dosya değil, derleme bulunamadığında da aynı istisna çıkar
FileNotFoundException yalnızca metin ya da veri dosyaları için fırlatılmaz; uygulamanın ihtiyaç duyduğu bir derleme (DLL) yüklenemediğinde de çıkabilir. Bu durumda mesaj, Could not load file or assembly gibi başlayarak bir derleme adından söz eder. Sorun artık veri dosyasının yolunda değil, eksik ya da çıktıya kopyalanmamış bir bağımlılıktadır. Önce mesajdaki derleme adını oku. Sonra NuGet paketlerinin geri yüklendiğinden (restore) ve projeye ilgili başvurunun eklendiğinden emin ol. Son olarak çıktı klasöründe o DLL'in bulunup bulunmadığına bak.
Sık Sorulan Sorular
Dosyayı proje klasörüne koydum, neden hâlâ bulunamıyor?
Uygulama çalışırken göreli yolu proje klasörüne göre değil, kendi çalışma klasörüne göre çözer; bu klasör genellikle derlenmiş çıktının bulunduğu yerdir. Dosyanın çıktı klasörüne kopyalanması için Visual Studio'da dosyanın özelliklerindeki Copy to Output Directory ayarına bakmalısın. Emin olmak için tam yolu yazdırıp File.Exists ile doğrula.
try-catch ile FileNotFoundException'ı yakalamak sorunu çözer mi?
Hayır, yalnızca programın çökmesini engeller ve kullanıcıya anlaşılır bir mesaj göstermeni sağlar. Dosya yine yerinde değildir. Önce nedeni bul: yol, ad ya da çıktıya kopyalanma. Sonra File.Exists ile önceden kontrol et. try-catch'i, beklenmedik durumlar için ikinci güvence olarak tut.
Kod bende çalışıyor ama arkadaşımın bilgisayarında FileNotFoundException veriyor, neden?
En sık nedenler şunlardır: kodda kendi bilgisayarına özgü sabit bir mutlak yolun yazılı olması, dosyanın çıktı klasörüne kopyalanmaması ve dosya adındaki harf ya da uzantı farkı. Dosyayı projeyle birlikte taşıyıp AppContext.BaseDirectory ve Path.Combine ile yol kurmak bu farkları azaltır. Hata bir derleme adından söz ediyorsa paketlerin o bilgisayarda geri yüklendiğini de kontrol et.
Bu hatayı çözerken sırayı izlemen yeterli: hangi dosya adı, hangi çalışma klasörü, dosya çıktıda var mı. Bu üç soruyu tam yol çıktısıyla yanıtladığında sorun genellikle kendini gösterir.