12. Python’da Dosya İşlemleri¶
Bu bölümde Python programlama dilini kullanarak sistemimizdeki dosyaları nasıl yöneteceğimizi öğreneceğiz. Konumuz temel olarak, bir dosyanın nasıl açılacağı, bu dosya üzerinde nasıl işlem yapılacağı ve dosya üzerindeki işlemler bittikten sonra bu dosyanın nasıl kapatılacağıdır.
İleride yazacağınız programlarda sıklıkla kullanacağınız bilgileri barındırdığı için, bu bölümü dikkatlice incelemenizi tavsiye ederim... O halde en temel bilgilerle başlayalım.
12.1. Varolan bir Dosyayı Okumak Üzere Açmak¶
Bir önceki bölümde modülleri işlerken “os” modülü içindeki “listdir()” adlı bir fonksiyon yardımıyla bilgisayarımızdaki dizinlerin içeriğini listelemeyi öğrenmiştik. Şimdiki bölümde ise, listelediğimiz bu dizinler içindeki dosyaları açmayı öğreneceğiz.
Diyelim ki bilgisayarımızda şu adda bir dosya var:
liste.txt
Bu dosya üzerinde herhangi bir işlem yapabilmek için, ilk iş olarak bu dosyayı açmamız gerekiyor. Dosyalarımızı Python ile açabilmek için open() adlı bir fonksiyondan yararlanacağız. Gelin isterseniz bu fonksiyonu kullanarak “liste.txt” adlı dosyamızı açalım:
>>> open("liste.txt")
Burada yaptığımız şey, “liste.txt” adlı dosyayı açmaktan ibaret. Yalnız biz burada, “liste.txt” adlı dosyanın o anda çalıştığımız dizin içinde olduğunu varsaydık. Yani bu dosyanın yukarıdaki komutla açılabilmesi için şu komutun çıktısında görünüyor olması lazım:
>>> os.listdir(os.curdir) #ya da os.listdir(os.getcwd())
Eğer bu dosya yukarıdaki komutun çıktısında görünmüyorsa, open() fonksiyonu içinde bu dosyanın tam yolunu belirtmemiz gerekir:
>>> open("/home/istihza/Desktop/liste.txt")
...gibi...
Yukarıdaki komutu verdiğimizde, “liste.txt” adlı dosyayı “salt-okunur” olarak açmış oluyoruz. Yani burada yaptığımız şey dosyayı sadece okumak üzere açmaktır. Dolayısıyla, dosyayı bu şekilde açtığımızda üzerinde değişiklik yapamayız. Sadece okuyabiliriz bu dosyayı...
“liste.txt” adlı dosyayı açmamızı sağlayan bu open() adlı fonksiyon ek olarak bir argüman daha alır. Örnek üzerinden görelim bunu:
>>> open("liste.txt", "r")
Burada “r” harfi” “read” kelimesinin kısaltmasıdır. Bu kelime Türkçe’de “okumak” anlamına gelir. Bu harfin görevi dosyayı “salt-okunur” kipte (sadece okumak üzere) açmamızı sağlamaktır... Eğer biz open() fonksiyonunun bu ikinci argümanını belirtmezsek, Python varsayılan olarak “r” argümanını vermişiz gibi davranacaktır. Dolayısıyla, open(“liste.txt”, “r”) yazmak ile open(“liste.txt”) yazmak arasında hiç bir fark yoktur...
“r” harfi dışında, open() fonksiyonuyla birlikte kullanabileceğimiz başka “kip belirleme harfleri” de bulunur. Bunları biraz sonra göreceğiz...
Python’da open() fonksiyonunu kullanarak bir dosyayı açmaya çalıştığımızda eğer herhangi bir hata ortaya çıkmadan imleç bir alt satıra geçiyorsa bu iyiye işarettir ve açmaya çalıştığımız dosyanın başarıyla açıldığını gösterir. Eğer Python açmaya çalıştığımız dosyayı bulamazsa bize şöyle bir hata verecektir:
>>> open("falanca.txt")
IOError: [Errno 2] No such file or directory: 'falanca.txt'
Gördüğünüz gibi, dosya bulunamadığında “IOError” adlı bir hata alıyoruz. Yazdığımız programlarda sıklıkla bu hatayı yakalamamız gerekecektir. Zira dosyalar ile uğraştığımız programlarda, bir dosyayı açarken, öncelikle o dosyanın sistemde var olup olmadığını kontrol etmek iyi bir yöntemdir:
>>> try:
... open("falanca.txt")
... except IOError:
... print("Böyle bir dosya yok!")
Böylece, eğer sistemde “falanca.txt” adlı bir dosya bulunmuyorsa, kullanıcılarımıza mantıklı bir hata mesajı göstermiş oluyoruz.
Python’da bir dosyayı okumak üzere nasıl açacağımızı gördük. Ama henüz dosyamızı okumadık... Peki yukarıda gösterildiği şekilde dosyaları açtıktan sonra bunların içeriğini nasıl görüntüleyeceğiz?
Okumak üzere açtığımız dosyaların içeriğini görüntülemenin en kolay yolu basit bir for döngüsü kurmaktır. Bunu nasıl yapacağımıza bakalım. Önce dosyamızı açıyoruz:
>>> dosya = open("python.txt")
Bu kısmı zaten biliyoruz. Şimdi bu dosya üzerinde bir for döngüsü kurarak dosya içeriğini görüntüleyelim:
>>> for satirlar in dosya:
... print(satirlar)
Bu döngü, “python.txt” adlı dosyanın bütün içeriğini ekrana dökecektir.
Böylece en basit şekilde, varolan bir dosyayı nasıl açıp okuyabileceğimizi görmüş olduk... Şimdi yolumuza dosyaların başka bir yönüyle devam edebiliriz.
12.2. Varolan Bir Dosyayı Yazmak Üzere Açmak¶
Bir önceki bölümde, varolan bir dosyayı “okumak” üzere nasıl açacağımızı öğrenmiştik. Bu bölümde ise varolan bir dosyayı “yazmak” üzere açacağız.
Hatırlarsanız, önceki bölümde dosyayı okumak üzere açmak için “r” adlı bir “kip değiştirme harfi”nden söz etmiştik. Bu harf, dosyayı okumak üzere açtığımızı gösteriyordu. Tıpkı buna benzer bir biçimde, varolan dosyalara yazabilmek için de bir kip değiştirme harfi kullanacağız. Bu seferki kip değiştirme harfimiz “a”. Bu harf İngilizce’deki “append” (eklemek, iliştirmek) kelimesinin baş harfidir. Önceki bölümde de söylediğimiz gibi, eğer dosyayı açarken herhangi bir kip değiştirici harf kullanmazsak, Python “r” yazmışız gibi davranacaktır. Dolayısıyla, eğer amacımız bir dosyayı okumak üzere değil de yazmak üzere açmaksa, ilgili kip değiştirme harfini (yani “a”yı) mutlaka belirtmemiz gerekir:
>>> dosya = open("falanca.txt", "a")
Eğer bilgisayarınızda “falanca.txt” adlı bir dosya varsa, bu komut varolan dosyayı açacaktır. Eğer böyle bir dosya yoksa, bu ada sahip yeni bir dosya oluşturulacaktır. Dolayısıyla bu komutu yeni bir dosya oluşturmak için de kullanabilirsiniz.
Şimdi bu “falanca.txt” adlı dosyanın içinde ne yazdığını kontrol edelim:
>>> for satirlar in dosya:
... print(satirlar)
Ne oldu? Hata aldınız, değil mi? Gayet normal... Çünkü biz dosyamızı yazmak üzere açtık... Okumak üzere değil... “a” ve “r” kipleri arasındaki bu fark çok önemlidir. Bu ikisi arasındaki farkı unutmamamız gerekir: “r” dosyayı okumamızı, “a” ise dosyaya yazmamızı sağlar... Eğer dosyanın içindekileri görmek istiyorsanız dosyayı şöyle açmanız gerekiyor:
>>> open("falanca.txt", "r") #veya "r" olmadan...
Neyse... Ne diyorduk? Evet... Şimdi bu dosyaya, aşağıda “metin” adlı bir değişken içine yerleştirdiğimiz satırları ekleyelim:
metin = """Python, pek çok dile kıyasla öğrenmesi kolay bir programlama
dilidir. Bu yüzden, eğer daha önce hiç programlama deneyiminiz olmamışsa,
programlama maceranıza Python'la başlamayı tercih edebilirsiniz."""
Bu satırları eklemek için write() adlı bir fonksiyondan faydalanacağız:
>>> dosya.write(metin)
Gördüğünüz gibi, bu write() adlı metodu doğrudan dosyanın üzerine uyguluyoruz...
Bu aşamada önemli bir noktadan bahsetmemiz gerekiyor. Python’da dosya işlemleri yaparken temel olarak şu üç aşamayı takip etmemiz gerekir:
- Dosyayı açmak
- Açtığımız dosya üzerinde işlem yapmak
- Son olarak da dosyayı kapatmak
Biz şimdiye kadar bu listedeki ilk iki işlemi yerine getirdik. Yani şimdiye kadar Python’la bir dosyanın nasıl açılacağını ve açılan bu dosya üzerinde nasıl işlem yapılacağını inceledik. Şimdi öğrenmemiz gereken şey dosyayı kapatmak olacaktır. Python’da açtığımız bir dosyayı kapatmak için close() adlı başka bir metottan yararlanacağız:
>>> dosya.close()
Yukarıdaki örneği basitleştirerek tekrar görelim:
metin = """Python, pek çok dile kıyasla öğrenmesi kolay bir programlama
dilidir. Bu yüzden, eğer daha önce hiç programlama deneyiminiz olmamışsa,
programlama maceranıza Python'la başlamayı tercih edebilirsiniz."""
Şimdi bu değişkeni kullanarak dosya işlemlerimizi gerçekleştirelim:
>>> dosya = open("falanca.txt", "a")
>>> dosya.write(metin)
>>> dosya.close()
Burada open() adlı fonksiyonu kullanarak öncelikle dosyamızı açtık. Daha sonra write() metodu yardımıyla dosya üzerinde bir işlem yaptık. En son da close() metodunu kullanarak dosyamızı kapattık. Eğer yazdığımız uygulamalarda, açtığımız bir dosyayı kapatmayı ihmal edersek, dosyamız üzerinde yaptığımız son değişiklikler dosyada görünmeyebilir. Ayrıca, kullandığımız işletim sisteminin yöntemlerini kullanarak (mesela dosyayı seçip “delete” tuşuna basarak) açık olan bir dosyayı silmeye çalışmak bizi hüsrana uğratacaktır...
Gelin isterseniz bu noktada bir nefes alıp, şimdiye kadar öğrendiğimiz şeyleri çok kısaca özetleyelim:
- Python’da bir dosyayı açmak için open() adlı bir fonksiyondan yararlanıyoruz.
- Eğer dosyamızı okumak üzere açacaksak kip değiştirme harfi olarak “r”yi kullanıyoruz.
- Eğer niyetimiz dosyaya yazmak ise kullanmamız gereken harf “a” olacaktır.
- Bir dosyaya ekleme yapmak için write() adlı bir fonksiyondan yararlanıyoruz.
- Üzerinde işlem yaptığımız bir dosyayı kapatmak için ise close() fonksiyonunu kullanıyoruz.
Yukarıdaki listeyi örneklerle anlatmamız gerekirse...
1:
>>> dosya = open("falanca.txt", "r") #dosyayı okuma kipinde açtık
2:
>>> dosya = open("falanca.txt", "a") #dosyayı yazma kipinde açtık
3:
>>> dosya.write("Merhaba Zalim Dünya!") #dosyaya ekleme yaptık
4:
>>> dosya.close() #dosyayla işimizi bitirip dosyamızı kapattık
Bir dosyayı okuma kipinde açtığımızda, basit bir for döngüsü yardımıyla dosyanın içeriğini görüntüleyebiliriz:
>>> for i in dosya:
... print(i)
Bir dosyayı nasıl açacağımızı, üzerinde işlem yapacağımızı ve bu dosyayı nasıl kapatacağımızı öğrendiğimize göre, “Python’da dosya işlemleri” konusunun başka bir yönünü incelemeye geçebiliriz...
12.3. Yeni bir Dosya Oluşturmak¶
Şimdiye kadar hep varolan dosyalar üzerinde çalıştık. Gerçi bir önceki bölümde öğrendiğimiz “a” adlı kip değiştirme harfi yardımıyla yeni bir dosya da oluşturabiliyoruz, ama bu bölümde tek görevi yeni bir dosya oluşturmak olan bir kip değiştirme harfinden söz edeceğiz... Bu harfin adı “w”dir. İngilizce “write” (yazmak) kelimesinin baş harfi olan “w”, bilgisayarımızda yeni bir dosya açmamızı sağlar. Hemen bir örnek verelim:
>>> dosya = open("yenidosya.txt", "w")
Bu komut, bilgisayarımızda “yenidosya.txt” adlı bir dosya oluşturacaktır. Yalnız bu harfi çok dikkatli kullanmamız gerekiyor. Eğer bilgisayarımızda “yenidosya.txt” adlı bir dosya halihazırda mevcutsa, yukarıdaki komut bu dosyanın içinde ne var ne yoksa silecektir... Daha doğrusu, bu komut aynı adlı eski dosyayı silip aynı adda başka bir dosya oluşturacaktır. Gördüğünüz gibi, “w” harfi saç-baş yoldurma potansiyeli taşıyan bir araç. O yüzden dikkatlice kullanılması gerekiyor.
12.4. Dosya Silmek¶
Artık Python’da dosya açmayı, dosya oluşturmayı ve dosya kapatmayı öğrendik. Peki ya biz bu dosyaları silmek istersek ne olacak? Bunun çok basit bir cevabı var. Python’daki hemen hemen her şeyde olduğu gibi, bu iş için de özel bir fonksiyondan yararlanacağız. Aslında bu fonksiyon daha önce öğrendiğimiz os adlı modülün metotlarından bir tanesidir. Dolayısıyla bu metodu kullanabilmek için öncelikle os modülünü içe aktarmamız gerekir. Dilerseniz bununla ilgili bir örnek verelim:
>>> import os
>>> os.remove("/home/istihza/Desktop/falanca")
Yukarıdaki komut, “/home/istihza/Desktop/” dizini içindeki “falanca” adlı dosyayı uçuracaktır. Ayrıca bu komutun, dosya silerken “emin misiniz?” tarzı bir soru sormadığına dikkatinizi çekmek isterim. Dolayısıyla bu komutu vermeden önce iki kez düşünmekte fayda var...
12.5. seek() ve tell() Metotları¶
Hatırlarsanız, okumak üzere açtığımız bir dosyanın içinde ne olduğunu görebilmek için for döngülerinden faydalanabileceğimizi söylemiştik. Yani bir dosyayı şu komutlar yardımıyla okuyabiliyorduk:
>>> dosya = open("falanca.txt")
>>> for i in dosya:
... print(i)
Dosyayı bu şekilde başarıyla okuyabildik. Şimdi bu dosyayı tekrar okumayı deneyelim:
>>> for i in dosya:
... print(i)
Ne oldu? Boş bir çıktı aldık, değil mi? Bu gayet normal. Çünkü bir önceki adımda dosyayı bir kez sonuna kadar okuduğumuz için, aynı dosyayı ikinci kez okumaya çalıştığımızda, zaten dosyanın sonuna varmış olmamızdan ötürü, Python bize boş bir çıktı verdi... Bunu, sonuna geldiğimiz bir kaseti tekrar dinlemeye çalışmaya benzetebiliriz (“kaset” diye bir şey vardı, hatırlıyorsunuz değil mi??).
Eğer sonuna geldiğimiz bir kaseti tekrar dinlemek istersek, öncelikle bu kaseti başa sarmamız gerekir. Aynı şekilde Python’da da bir dosyayı sonuna kadar okuduktan sonra tekrar okumak istersek bu dosyayı başa sarmamız gerekecek. Bu iş için seek() adlı bir metottan yararlanacağız. Şimdi dosyamızı başa saralım:
>>> f.seek(0)
Böylece dosyamızı 0. bayta, yani en başa geri almış olduk. Şimdi dosyayı tekrar okuyabiliriz:
>>> for i in dosya:
... print(i)
seek() metoduna sadece “0” parametresini verip dosyanın 0. baytına gitmek mecburiyetinde değiliz. Eğer biz istersek, seek() metodunu kullanarak dosyanın istediğimiz baytına atlayabiliriz. Bu konunun daha somut bir şekilde anlaşılabilmesi için isterseniz dosyamızın içinde şu satırların olduğunu varsayalım:
birinci satır
ikinci satır
üçüncü satır
Şimdi bu dosyanın 10. baytına gidiyoruz:
>>> f.seek(10)
Dediğim gibi, bu komut, bizi alıp dosyanın 10. baytına götürecektir. Dolayısıyla bu komuttan sonra aşağıdaki komutu verecek olursak, Python okumaya 10. bayttan başlar:
>>> for i in dosya:
... print(i)
...
tır
ikinci satır
üçüncü satır
Çok kaba bir şekilde ifade edecek olursak, çoğunlukla “10. bayt” demek “10. karakter” demek gibidir. Mesela yukarıdaki örnekte “seek(10)” komutu bizi 10. karakterin başına götürdü... Ama bunun her zaman böyle olmayacağını da asla aklımızdan çıkarmıyoruz. Çünkü her karakter 1 bayt değerinde olmayabilir. Bazı karakterler 1’den fazla bayttan oluşur. Dolayısıyla “1 bayt = 1 karakter” şeklindeki bir düşünce bizi yanlış sonuçlara götürür.
Dediğimiz gibi, seek() fonksiyonunu kullanarak bir metnin herhangi bir baytına gidebiliriz. Peki o anda bir metnin kaçıncı baytında olduğumuzu nasıl öğreniriz? Tabii ki tell() adlı metodu kullanarak:
>>> dosya.tell()
Bu komut bize o anda metnin kaçıncı baytında olduğumuzu söyleyecektir. Henüz bir dosyayı parça parça okumamaızı sağlayacak fonksiyonları görmediğimiz için, seek() metodunu kullanarak bir dosyanın belirli bir baytına gitmediğimiz sürece, tell() komutu bize ancak bir dosyanın 0. veya sonuncu baytında olduğumuzu söyleyebilecektir. Ama hiç merak etmeyin. Bu bahsettiğimiz fonksiyonları şimdi göreceğiz...
12.6. read(), readline(), readlines() Metotları¶
Python’da dosya işlemlerine ilişkin temel bazı bilgileri edindiğimize göre, bu konuya ilişkin önemli bazı fonksiyon ve metotları incelemeye geçebiliriz. Python’da dosyaları işlerken kullanabileceğimiz çok önemli üç adet metot bulunur. Bunlar read(), readline() ve readlines() adlı metotlardır. Bu metotlar birbirine benzese de aralarında önemli bazı farklar bulunur.
Şimdi şu komutları çalıştıralım:
>>> f = open("deneme.txt", "w")
>>> f.write("birinci satır\n")
>>> f.write("ikinci satır\n")
>>> f.write("üçüncü satır\n")
>>> f.close()
Yukarıdaki komutlar yardımıyla önce “deneme.txt” adlı bir dosya oluşturduk. Burada “w” harfini kullandığımıza dikkat edin. Eğer bilgisayarımızda “deneme.txt” adlı bir dosya yoksa bu “w” harfi sayesinde “deneme.txt” adlı bir dosya oluşturulacaktır. Eğer zaten böyle bir dosya varsa, bu dosya silinip yerine aynı adla başka bir dosya gelecektir...
Daha sonra art arda üç satır ekliyoruz “deneme.txt” adlı dosyamıza. Bunu yaparken write() fonksiyonundan yararlandığımıza dikkat edin. Son olarak da close() metodunu kullanarak dosyamızı kapatmayı ihmal etmiyoruz.
Bu arada her bir write() komutundan sonra etkileşimli kabukta “14”, “13”, “13” gibi rakamlar görmüş olmalısınız. Bu rakamlar sizin write() metodunu kullanarak dosyaya eklediğiniz karakter dizisinin kaç bayt olduğunu gösteriyor...
Şimdi dosyamızı okuma kipinde tekrar açalım:
>>> f = open("deneme.txt")
Burada bu komutu istersek şöyle yazabileceğimizi de biliyoruz:
>>> f = open("deneme.txt", "r")
Bildiğiniz gibi, biz “r” harfini kullansak da kullanmasak da Python o harf oraya yazılmış gibi davranacaktır...
Şimdi bu dosyamızın içeriğine bakalım:
>>> for i in f:
... print(i)
...
birinci satır
ikinci satır
üçüncü satır
Daha önce de dediğimiz gibi, dosyaları okumak için for döngüleri basit ve pratik bir araçtır. Ama şimdi göstereceğimiz yöntem bize bu iş için daha da pratik bir yol sunar. Bu yöntemin adı read() metodudur... Hemen deneyelim:
>>> print(f.read())
Eğer bu komutun çıktısı boş ise, ya açmaya çalıştığınız dosya boştur, ya da seek(0) metodunu kullanarak dosyanın en başına sarmamışsınızdır. Eğer dosyanın boş olmadığından eminseniz şu komutu vererek dosyayı en başa sarın:
>>> seek(0)
Şimdi komutumuzu tekrar verelim:
>>> print(f.read())
birinci satır
ikinci satır
üçüncü satır
Bu read() metodunu kullanarak dosyadan istediğimiz sayıda bayt da okuyabiliriz:
>>> print(f.read(7))
birinci
Yukarıdaki komut ile, “f” adlı dosyadan 7 baytlık bir kısmı okumuş olduk... Aynı komutu tekrar verelim:
>>> print(f.read(7))
ikinci
Gördüğünüz gibi, o anda dosyanın hangi noktasında olduğumuza bağlı olarak dosyanın farklı kısımları okunuyor... O anda dosyanın kaçıncı baytında olduğumuzu öğrenmek için tell() adlı metottan yararlanmamız gerektiğini biliyoruz:
>>> f.tell()
Şimdiye kadar dosyalarımızı hep bir bütün olarak okuduk. Ama eğer istersek, readline() adlı bir metot yardımıyla dosyamızı satır satır da okuyabiliriz:
>>> print(f.readline())
birinci satır
Gördüğünüz gibi bu komutla dosyanın bütününü bir anda değil, sadece ilk satırı okuduk. Şimdi aynı komutu tekrar verelim:
>>> print(f.readline())
ikinci satır
Bu defa dosyanın ikinci satırını elde ettik. Devam edelim:
>>> print(f.readline())
üçüncü satır
Tıpkı read() metodunda olduğu gibi, readline() metoduna isterseniz parametre olarak bir sayı verip, o verdiğiniz sayı kadar bayt okuyabilirsiniz dosyadan:
>>> print(f.readline(7))
birinci
Bütün bu örneklerden anladığımız gibi, read() metodu bir dosyanın tamamını bir anda okuturken, readline() metodu aynı dosyayı satır satır okumamıza imkan tanıyor. Peki başlıkta gördüğümüz readlines() metodu ne işe yarıyor? Hemen görelim:
>>> print(f.readlines())
['birinci satır\n', 'ikinci satır\n', 'üçüncü satır\n']
Bu metodun çıktısı bir listedir. Bu listede, dosya içindeki bütün satırlar tek tek yer alır. Ayrıca dikkat ederseniz satır sonlarına işaret eden “n” kaçış dizisi de çıktıda belirgindir. Elde ettiğimiz çıktı bir liste olduğu için, dosyadaki satırlara tek tek erişebiliriz:
>>> f.seek(0) #dosyamızı başa saralım...
>>> satırlar = f.readlines() #kolay erişim için f.readlines() komutunu değişkene atadık
>>> satırlar[1] #şimdi de tek tek satırlara erişelim...
'ikinci satır\n'
>>> satırlar[2]
'üçüncü satır\n'
>>> satırlar[0]
'birinci satır\n'
>>> f.close() #eğer işimiz bittiyse dosyamızı kapatalım
Öteki iki metotta olduğu gibi, readlines() metoduna da istenirse parametre olarak bir sayı verilebilir. Ancak readlines() metoduna verilen bu sayı biraz farklı bir işlev görecektir. Bakalım:
>>> print(f.readlines(4))
['birinci satır\n']
Burada “4” sayısını vermemize rağmen sadece 4 bayt okunmadığına dikkat edin. Şimdi şu örneğe bakalım. Bu örnek durumu biraz aydınlatacaktır:
>>> print(f.readlines(15))
['birinci satır\n', 'ikinci satır\n']
Gördüğünüz gibi, readlines() metodu her koşulda satır sonuna ulaşıyor. Eğer parametre olarak verdiğimiz sayı bir satırdan az sayıda bayt içeriyorsa sadece bir satır çıktı olarak veriliyor. Eğer parametredeki sayı bir satırdaki bayt sayısını aşıyorsa, bu bayt sayısı ikinci satırın tamamını karşılamasa bile, birinci satırla birlikte ikinci satırın tamamı da ekrana dökülüyor... Bu özelliği, bir satırındaki bayt sayısını tam olarak bilmediğiniz, ama dosyanın büyüklüğünden ötürü tamamını da okumak istemediğiniz dosyalar üzerinde kullanabilirsiniz...
12.7. Dosyalarda Karakter Kodlaması (encoding)¶
Bazen internette dolaşırken kimi Türkçe sayfalardaki harflerin bozuk olduğunu görürüz. Yani hemen hemen herkes hayatı boyunca en az bir kez şuna benzer bir görüntüyle karşılaşmıştır:
Python nesne y?nelimli, yorumlanabilen, birimsel(mod?ler) ve etkile?imli bir programlama dilidir. Girintilere dayal? basit s?zdizimi, dilin Ã?renilmesini ve ak?lda kalmas?n? kolayla?t?racakt?r. Bu da ona s? diziminin ayr?nt?lar? ile vakit yitirmeden programlama yap?lmaya ba?lanabilen bir dil olma ?zelli?i kazand?r?r.
Buradaki sorun, sayfanın karakter kodlamasının düzgün yapılmamış olmasıdır. Biz bu durumu internet tarayıcılarımızın “dil kodlaması” (veya “kodlama”) ayarlarının yapıldığı bölümden uygun bir dili veya kodlamayı seçerek düzeltebiliriz. Bu ayarlarda genellikle tercih edeceğimiz kodlama “Utf-8” olacaktır. Python programlama dili de varsayılan olarak “utf-8” kodlamasını kullanır. Bu kodlama yardımıyla dünya üzerindeki pek çok dile ait özel karakterleri rahatlıkla görüntüleyebiliyoruz. Konuya işletim sistemleri çerçevesinden bakacak olursak, GNU/Linux’ta utf-8 kodlamasını kullanarak sorunsuz bir şekilde çalışabiliyoruz. Ancak Windows üzerinde bazen utf-8 kodlaması görüntüleme hatalarına yol açabilir. Windows sistemlerinde yaygın olan karakter kodlaması (Türkçe için) cp1254’tür. Bu yüzden yazdığımız bir Python programında Türkçe karakterler kullanacağımız zaman, dosyamızın karakter kodlamasını açık bir şekilde belirtmemiz gerekebilir.
Dediğim gibi, Python varsayılan olarak utf-8 kodlamasını kullanır. Bu kodlama biçimi, GNU/Linux sistemlerinde Türkçe harfleri rahatlıkla göstermemizi sağlarken, bazı Windows sistemlerinde sorun yaratabilir. Eğer yazdığınız bir programda kullandığınız Türkçe harfler düzgün görünmüyorsa veya Python bu programın çalışması sırasında hata veriyorsa, betiğinizin en başına şu satırı eklemeniz gerekebilir:
#-*-coding:cp1254-*-
Buna benzer bir durum dosyalarla çalışırken de karşımıza çıkabilir. Bazı dosyaları açmaya çalışırken şuna benzer bir hata mesajıyla karşılaşabiliriz:
UnicodeEncodeError: 'charmap' codec can't encode characters
in position x-y: character maps to <undefined>
Bu durumu engellemek için, dosya açarken mutlaka encoding seçeneğini de belirtmemiz gerekir:
>>> dosya = open("deneme.txt", "r", encoding="utf-8")
Gördüğünüz gibi, open() fonksiyonu toplam üç parametre alıyor. İlk iki parametreyi daha önce görmüştük. Üçüncü parametre olan encoding dosyanın karakter kodlamasını belirlememizi sağlıyor. Eğer biz açtığımız bir dosyada encoding parametresini belirtmezsek, Python otomatik olarak varsayılan karakter kodlamasını kullanacaktır. encoding parametresini belirtmeden açtığınız bir dosyanın karakter kodlamasını iki şekilde öğrenebilirsiniz:
1:
>>> dosya.encoding
utf-8
Bu komut GNU/Linux üzerinde verildiği için çıktımız “utf-8”. Eğer aynı komutu Windows üzerinde verirseniz çıktınız muhtemelen “cp1254” olacaktır.
2:
>>> import locale
>>> locale.getpreferredencoding()
utf-8
Bu komut da tıpkı bir önceki komut gibi GNU/Linux üzerinde verilmiştir. Bu yüzden buradaki çıktı utf-8. Eğer bu komutu Windows’ta verirseniz çıktınız büyük ihtimalle “cp1254” olacaktır. Gördüğünüz gibi, ikinci komutta locale adlı modülün getpreferredencoding() adlı fonksiyonundan yararlandık... Eğer açtığınız bir dosyada özel olarak bir karakter kodlaması belirtmediyseniz, encoding niteliğinin çıktısı ile locale.getpreferredencoding() fonksiyonunun çıktısı aynı olacaktır.
12.8. İkili Dosyalar (Binary Files)¶
Şimdiye kadar hep metin dosyaları ile çalıştık. Şu ana dek öğrendiğimiz bilgilerle, içeriğinde bir metin barındıran dosyaları okuyabilir, bu dosyalara yazabilir ve bu dosyaları güvenli bir şekilde kapatabiliriz. Çok kaba bir şekilde ifade etmemiz gerekirse, eğer bir dosyayı herhangi bir metin düzenleyici ile açabiliyorsak, bu dosyalara şimdiye kadar öğrendiğimiz bilgileri uygulayabiliriz... Ancak karşımıza her zaman sadece metin içeren dosyalar çıkmayabilir. Bazen de “ikili” (binary) biçimdeki dosyalarla uğraşmamız gerekebilir. Mesela resim dosyaları birer ikili dosyadır ve bunları şimdiye kadar öğrendiğimiz bilgilerle açıp okuyamayız veya bunlara herhangi bir şey yazamayız. Python’da ikili dosyalarla çalışabilmek için özel bir kip değiştirme harfinden yararlanacağız.
Bildiğiniz gibi, şimdiye dek Python’da üç adet kip değiştirme harfi gördük. Bunlar, “r” (okuma), “a” (yazma) ve “w” (oluşturma) harfleri idi. Bu bölümde bu harflere bir yenisini daha ekleyeceğiz. Burada göreceğimiz harf “binary” kelimesinin baş harfi olan “b”dir...
Bu “b” harfini tek başına kullanmıyoruz. Bunu daha önce öğrendiğimiz o üç harfle birlikte kullanacağız. Mesela ikili düzendeki bir dosyayı okumak üzere açmak için şu komutu yazacağız:
>>> dosya = open("falanca.bin", "rb")
Hatırlarsanız, metin dosyalarını okumak üzere açarken “r” harfini belirtmesek de oluyordu. Ama ikili dosyaları okumak üzere açarken, bu dosyanın kipini mutlaka belirtmemiz gerekir.
İkili dosyaları yazmak üzere açarken ise şöyle bir komut kullanacağız:
>>> dosya = open("falanca.bin", "ab")
Gördüğünüz gibi, yaptığımız şey önceden bildiğimiz “a” harfinin sağına bir adet “b” harfi eklemekten ibarettir... Yeni bir ikili dosya oluşturabilmek için de yine benzer bir yöntem kullanıyoruz:
>>> dosya = open("falanca.bin", "wb")
Metin dosyalarını okurken karakter dizilerine bakıyoruz. İkili dosyalarda baktığımız şey ise baytlardır. Yani metin dosyaları bize karakter karakter gelirken, ikili dosyalar bayt bayt gelecektir:
>>> ikili = open("logo.jpeg", "rb")
>>> oku = ikili.read()
>>> len(oku)
27429
Demek ki benim elimdeki “logo.jpeg” dosyası 27429 bayt uzunluğundaymış. Eğer dosyanızın özelliklerine bakacak olursanız, dosyanın boyut kısmındaki rakamın len() fonksiyonundan aldığımız rakamla aynı olduğunu göreceksiniz.
Bu arada, eğer bu ikili dosyayı daha önce öğrendiğimiz şekilde açıp okumaya çalışırsanız Python size hata mesajı gösterecektir:
>>> dosya = open("logo.jpeg")
>>> oku = dosya.read()
UnicodeDecodeError: 'charmap' codec can't decode byte
0x8e in position 1254: character maps to <undefined>
Gördüğünüz gibi, Python bu şekilde ikili dosya içindeki baytları doğal olarak tanıyamıyor... Dolayısıyla ikili dosyaları açarken, kullanacağımız kip değiştirme harfine dikkat etmemiz gerekiyor.