BİL203U-PROGRAMLAMA II
Ünite 5: Dosya İşlemleri ve Hata Yakalama
Giriş
Dosyalar günlük hayatımızda sıklıkla kullandığımız bir dijital ortam bileşenidir. Gerek iş hayatındaki işlemlerin yapıldığı excel dosyaları, gerek yazışmaların ve dokümanların takip edildiği word dosyaları olsun, hepsi bilgisayar için 0 ve 1 sayılarından oluşan verilerdir. Bunun yanında dosyaların kullanımı sadece görüldüğü alanlarla sınırlı değildir. Bir işletim sisteminin çalışması, veritabanındaki verilerin tutulması, programların gerekli ayarlarının tutulduğu dosyalar gibi kullanıcıya açık olmayan çok fazla işlem dosyalar ile gerçekleştirilmektedir.
Dijital ortamda kullanılan tüm bu dosyaların bir şekilde depolanması ve üzerlerinde gerekli işlemlerin yapılması gerekmektedir. Programlama dillerinde, farklı dosya türlerinde işlem yapabilmek için özelleşmiş kütüphaneler bulunmaktadır.
Dosya İşlemleri
Dosyalar
Dosyalar, ilgili bilgileri depolamak için disk üzerindeki isimlendirilmiş konumlardır. Verileri kalıcı olarak sabit disk, hafıza kartı gibi kalıcı bir bellekte depolamak için kullanılırlar. Rastgele Erişimli Bellek (RAM) geçici bir bellek türüdür, yani bilgisayar kapatıldığında veriler silinir. Bu yüzden verileri kalıcı olarak depolayarak gelecekte kullanmak üzere dosyalardan faydalanılır.
Bir dosyadan okumak veya bir dosyaya yazmak istendiğinde, ilk önce dosyanın açılması gerekmektedir. Dosya ile ilgili yapılacak işlemler tamamlandığında, dosyaya bağlı kaynakların serbest kalması için kapatılması gerekmektedir. Python’da bir dosya işlemi aşağıdaki sırayla gerçekleşmektedir:
• Bir dosya aç • Okuma veya yazma işlemleri • Dosyayı kapat
Dosya Açma
Python, bir dosyayı açmak için dahili bir open() fonksiyonuna sahiptir. Bu fonksiyon, dosyayı uygun şekilde okumak veya değiştirebilmek için tanımlayıcı olarak da adlandırılan bir dosya nesnesi döndürmektedir.
Python programlama dilinde, bir dosya açarken mod belirtilebilir. Modda, dosyaya “r” okuma, “w” yazma veya “a” ekleme durumlarından biri belirtilebilir. Ayrıca dosyanın metin modunda veya ikili (binary) modda açılması da parametrik olarak belirtilebilir. Dosyanın varsayılan okuma modu ise metin modudur. Bu modda, dosyadan okurken dizeler (string) alınmaktadır. Bunun yanında, ikili mod bayt değer döndürmektedir. Bu mod, resim veya yürütülebilir dosyalar (exe uzantılı) gibi metin olmayan dosyalarla uğraşırken kullanılacak moddur.
Python programlama dilinde diğer dillerden farklı olarak, a karakteri ASCII kodlaması kullanılarak kodlanana kadar 97 sayısını işaret etmez. Bunun yanında, varsayılan kodlama
platforma bağlıdır ve Linux’ta utf-8 iken Windows’ta cp1252’dir. Bu yüzden, varsayılan kodlamaya dayalı dosya işlemleri sorun çıkarabilir, hazırlanan kodun farklı platformlarda farklı davranacağı göz önüne alınmalıdır. Böyle hatalara neden olmaması için, metin modunda dosyalarla çalışırken, kodlama türünün belirtilmesi gerekmektedir.
Dosya Kapatma
Dosya üzerinde yapılan işlemler bittiğinde dosyanın düzgün bir şekilde kapatılması gerekmektedir. Bir dosya kapatılarak, dosyaya bağlı olan kaynaklar serbest bırakılmaktadır. Dosya kapatma işlemi close() yöntemi kullanılarak yapılmaktadır.
Python’da, artık başvurulmayan nesneleri temizlemek için bir çöp toplayıcısı (Garbage Collector) yapısı bulunmaktadır, fakat dosya kapatma işlemleri için bu yapıya güvenilmemelidir.
Bu yöntem de tamamen güvenli değildir. Dosya ile işlem yaparken bir hata oluştuğunda, kod dosyayı kapatmadan çıkacaktır. Bu yüzden daha güvenli bir yol olan, hata yakalama amacıyla kullanılan try...finally bloğu kullanılmalıdır.
Bir dosyayı kapatmanın en iyi yolu “with” deyiminin kullanılmasıdır. “with” deyimi sayesinde, with ifadesinin içindeki bloktan çıkıldığında dosyanın kapatılması sağlanmaktadır. Ayrıca close() fonksiyonu dahili olarak çağrıldığı için tekrar çağrılmasına gerek duyulmaz.
Dosyaya Yazma
Python’da bir dosyaya veri yazmak için onu “w” yazma, “a” ekleme veya “x” özel oluşturma modunda açılması gerekmektedir. Dosya mevcutsa, var olan dosyadaki tüm verileri silerek üzerine yazacağı için “w” modunun kullanımına dikkat edilmesi gerekmektedir.
Bir metin dizisi veya bayt dizisi yazmak için (ikili dosyalarda) write() metodu kullanılmaktadır. Bu metot, dosyaya yazılan karakter sayısını döndürmektedir.
Dosya yazma işlemlerinde dikkat edilmesi gereken bir nokta da, farklı satırları ayırt etmek için yeni satır karakterlerinin kod ile eklenmesi gerekmektedir.
Dosya Okuma
Python programlama dilinde bir dosyayı okuyabilmek için, dosya okuma “r” modunda açılmalıdır. Dosyadan okuma yapmak için çeşitli yöntemler mevcuttur. Verilerin boyut kadar veri okumak için read(boyut) yöntemi kullanılabilir. Boyut parametresi belirtilmezse, dosyanın sonuna kadar olan tüm verileri döndürür.
Dosya okuma kodunda, read() yöntemi verilen sayı kadar karakter döndürür. Dosyanın sonuna ulaşıldığında, daha fazla okuma yapılamadığı için boş veri dönmektedir.
Mevcut dosya imleci (konumu) search() yöntemi kullanılarak değiştirilebilir. Benzer şekilde, tell() yöntemi
mevcut imleç konumunu (bayt sayısı olarak) döndürmektedir.
Dosya okumak için for döngüsü de kullanılabilir. Dosya içeriği, döngü sayesinde verimli ve hızlı bir şekilde satır satır okunmaktadır.
Alternatif olarak, bir dosyanın tek tek satırlarını okumak için readline() yöntemi kullanılabilir. Bu yöntem ile, yeni satır karakteri de dahil olmak üzere dosya satır satır okunarak veri döndürülür.
Son olarak da, readlines() fonksiyonu dosyanın tüm kalan satırlarının bir listesini döndürmek için kullanılır. Tüm bu okuma yöntemleri, dosyanın sonuna (EOF) ulaşıldığında boş değer döndürmektedir (kitabın 163. sayfasındaki tablo 5.2'de Python Dosya Metotları incelenebilir).
Dizinler
Dizin veya çok kullanılan diğer adıyla klasör, dosyalar ve alt klasörlerden oluşan bir koleksiyon yapısıdır. Hazırlanan programda çok sayıda dosya ile işlem yapılacaksa, operasyonu daha yönetilebilir kılmak için dizin yapısından faydalanılabilir.
Python programlama dilinin standart modülleri altında gelen “os”, yani işletim sistemi modülü ile dizin işlemleri gerçekleştirilmektedir. Bu modül, işletim sistemiyle etkileşim için fonksiyonlar sağlamaktadır. *os* ve *os.path* modülleri, dosya sistemiyle etkileşim kurmak için birçok fonksiyon içermektedir.
Geçerli Dizini Alma
Geçerli Çalışma Dizini (CWD), Python kodunun çalıştığı bir klasör olarak düşünülebilir. Dosyalar yalnızca adlarıyla çağrıldığında, Python yorumlayıcısı bunun CWD’de başladığını varsayarak işlem yapar.
Programın mevcut çalışma dizini (Current Working Directory-CWD), os modülünün getcwd() yöntemi kullanılarak elde edilebilir. Bu yöntem, geçerli çalışma dizinini bir dize biçiminde döndürmektedir.
Dizini Değiştirme
Mevcut çalışma dizini (CWD) değiştirmek için os.chdir() yöntemi kullanılmaktadır. Bu yöntem, CWD’yi belirtilen bir dosya yolu ile değiştirir. Yeni bir dizin yolu olarak yalnızca tek bir argüman alır. Yeni dizin yolu elemanlarını ayırmak için hem ters bölü “\” hem de “/” bölü işareti kullanılabilir.
Dizinleri ve Dosyaları Listeleme
Bir dizindeki tüm dosya ve alt dizinlere listdir() fonksiyonu kullanılarak elde edilebilir. Bu fonksiyon parametre olarak bir dosya yolu alır ve bu dosya yolundaki alt dizinlerin ve dosyaların bir listesini döndürür. Yol belirtilmezse, geçerli çalışma dizinindeki alt dizinlerin ve dosyaların listesini döndürür.
Yeni Dizin Oluşturma
Yeni bir dizin oluşturmak için os modülünün desteklediği os.mkdir() fonksiyonu bulunmaktadır. Bu fonksiyona parametre olarak verilen, “dosya yolu” isimli bir dizin oluşturmak için kullanılır. Oluşturulacak dizin zaten mevcut ise, bu yöntem FileExistsError hatası verecektir.
Bir Dizini veya Dosyayı Yeniden Adlandırma
Bir dizini veya dosyayı yeniden adlandırmak için rename() fonksiyonu kullanılmaktadır. Bu fonksiyon iki temel parametre almaktadır. Bunlardan ilki eski isim, ikinci parametre de yeni isim değerleridir.
Dizin veya Dosyayı Kaldırma/Silme
Bir dosyayı kaldırmak, silmek için remove() yöntemi kullanılmaktadır. Boş bir dizini kaldırmak da rmdir() metodu yardımı ile gerçekleştirilmektedir.
İstisnalar (Exceptions)
Program yazarken programcıların ve son kullanıcıların karşılaştıkları hatalar vardır. Genel olarak 3 farklı şekilde hataları gruplayabiliriz.
1. Program Hataları (Syntax errors) 2. Mantık Hataları (Bug) 3. İstisnalar (Exceptions)
Program Hataları (Syntax Errors)
Programlama dilinin söz dizimine uygun olmayan kod yazılması nedeniyle ortaya çıkan hataya yazım (syntax) veya çözümleme (parsing) hatası denilmektedir.
Mantık Hataları (Bug)
Mantık hatalarının fark edilmesi, yazım hatalarına göre daha zordur. Program çalışırken işleyişe müdahale edecek, sonlanmasına neden olacak bir hata oluşmaz. Fakat, istenilenden daha farklı sonuç veriyor olması ile bu mantık hataları ortaya çıkmaktadır.
İstisnalar (Exceptions)
Söz diziminden başarılı bir şekilde geçtikten sonra oluşan hatalara istisna denilmektedir. Sayının sıfıra bölünmesi, olmayan bir dosyaya erişim veya içe aktarılmaya çalışılan bir modülün bulunmaması gibi hatalar bunlara örnek verilebilir.
Bu şekilde bir çalışma zamanı hatası meydana geldiğinde, Python programlama dili bir istisna nesnesi oluşturmaktadır. Eğer olası hatalar düzgün bir şekilde ele alınarak kullanıcıyı uyarmazsa, yorumlayıcı hatanın neden olduğu hakkında bir geri bildirimi ekrana yazdıracaktır.
Phyton Dilindeki Dahili/Yerleşik İstisnalar
Programlama dilinin izin vermediği işlemler istisnalar oluşturabilir. Python dilinde, ilgili hatalar oluştuğunda ortaya çıkan, birçok dahili tanımlanmış istisna mevcuttur. Yerleşik local() işlevini kullanarak tüm yerleşik istisnalara ulaşılabilir.
locals()[‘__builtins__’] fonksiyonu yardımıyla, dahili istisnalar, fonksiyonlar ve niteliklerden oluşan bir modül
elde edilir. Elde edilen bu modülün özniteliklerinin metin dizeleri olarak listelenmesi ise “dir” fonksiyonu vasıtasıyla gerçekleşir (kitabın 170. sayfasındaki tablo 5.3'te Python Yerleşik İstisnalar ve Nedenleri incelenebilir).
İstisna/Hata Yakalama
Python programlama dili de, diğer yüksek seviyeli diller gibi hata yakalama mekanizmasına sahiptir. Programda bir hata oluştuğunda, bir şeyler ters gittiğinde hata yakalayabilmek için try, except ve finally işlevleri kullanılmaktadır.
Hata Yakalama
Hata yakalamak için try ifadesi kullanılmaktadır. Kod içerisinde bir hata/istisna oluşturabilecek durumlar try cümleciği içerisinde yazılır. Kodun üreteceği herhangi bir hata durumunda, except yan cümleciği içerisinde yazılan kod bloğu çalışacaktır. Böylece bir hata durumunda yapılması gereken işlem kullanıcı tarafından belirlenmiş olacaktır.
Belirli İstisnaların Yakalanması
Program yazarken tüm hataları aynı şekilde ele alan bir kod hazırlanması tavsiye edilen bir durum değildir. Bir hata yakalanırken except ifadesi ile hangi türde hataların yakalanması gerektiği belirtilebilir. Kod içerisindeki try ifadesi ise birden fazla except ifadesine sahip olabilir. Herhangi bir hata oluştuğu durumda ise sadece bir except ifadesi çalıştırılacaktır. Bir except ifadesi içinde de bir değer kümesi ile farklı hatalar tanımlanabilmektedir.
İstisna Oluşturma/Hata Fırlatma
Python programlama dilinde, istisnalar çalışma zamanında hatalar meydana geldiğinde ortaya çıkmaktadır. Ayrıca, “raise” anahtar sözcüğü kullanılarak istisnalar kod tarafında da kullanıcı tarafından oluşturulabilir. Programcı tarafından oluşturulan istisnanın sebebini açıklamak için de, isteğe bağlı olarak istisnaya parametre gönderilebilir.
Hata Yakalamada Else Bloğu
Program akışına bağlı olarak kimi durumlarda, “try” hata yakalama bloğunda hata olmadan çalıştığında bir kod bloğunun çalıştırılması gerekebilir. Bu gibi durumlarda “else” bloğundan faydalanılabilir. Else bloğu, try bloğundan sonra çalıştırılacağı için hata yakalama işlemlerinden bağımsızdır.
try…finally Bloğu
Hata yakalama koduna isteğe bağlı olarak “finally” bloğu eklenebilir. Bu kod bloğu, ister hata olsun ister olmasın çalıştırılır. Genellikle kodda kullanılan dış kaynakların serbest bırakılması amacıyla kullanılır.
Örneğin bir dosya, veritabanı veya network üzerinden yapılan bir işlemde, yapılan işlem başarılı olsun olmasın kullanılan kaynakların serbest bırakılması veya temizlenmesi, bağlantının kapatılması gibi işlemler gerekmektedir. finally bloğu ile tüm bu işlemler gerçekleştirilebilir.
Kullanıcı Tanımlı Hata Yakalama
Python programlama dilinde yerleşik olarak gelen çok sayıda hata yakalama durumları mevcuttur. Ancak kimi durumlarda kullanıcılar, programın akışına özel olarak tasarlanmış kendi istisnai durumlarını oluşturabilirler.
Kullanıcı tanımlı bir istisna oluşturabilmek için yeni bir sınıf oluşturulmalıdır. Oluşturulan yeni istisna sınıfı, doğrudan veya dolaylı olarak yerleşik olan “Exception” sınıfından türetilmesi gerekmektedir.
Benzer şekilde, büyük bir projede kullanıcı tanımlı istisnalar tek bir dosya altında toplanarak kontrol edilmesi de tavsiye edilen bir kodlama uygulamasıdır. Standart modüllerin çoğunda genellikle istisnalar “exceptions.py” veya “errors.py” şeklinde isimlendirilen dosyalarda tanımlanmaktadır.
Kullanıcı tanımlı istisna sınıfları da diğer sınıfların sahip olduğu özelliklere sahiptir ve normal bir sınıf ile yapılabilecek her şey bu sınıf yardımıyla da yapılabilir. Bu sınıfların daha sade ve anlaşılır şekilde kullanılması da tavsiye edilmektedir.
OzelHata adında istisnalar için bir temel sınıf tanımı yapılmıştır. Program tarafından oluşturulan diğer iki (KucukDegerHatasi ve BuyukDegerHatasi) istisnaları da yine bu temel sınıftan türetilmiştir. Python programlama dilinde standart olarak kullanıcı tanımlı istisnalar bu şekilde tanımlanmaktadır, ancak farklı yöntemler de kullanılabilir.