Dosya İşlemleri¶
Bu bölümde Python programlama dilini kullanarak dosyaları nasıl yöneteceğimizi, yani nasıl yeni bir dosya oluşturacağımızı, bir dosyaya nasıl bir şeyler yazabileceğimizi ve buna benzer işlemleri öğreneceğiz. Esasında biz bundan önceki bazı derslerimizde bu konuya üstünkörü de olsa değinmiştik. İşte bu bölüm, daha önce görüp de tam olarak anlayamadığımız bazı kod parçalarını çok daha iyi anlayabilmemizi sağlayacak bilgileri edineceğimiz bir bölüm olacak.
Hatırlarsanız os modülünü anlatırken Windows için startfile() adlı bir fonksiyondan, GNU/Linux için ise xdg-open adlı bir sistem komutundan söz etmiştik. Bu araçlar yardımıyla, bilgisayarımızda bulunan dosyaları (ve programları), sistemdeki varsayılan uygulama ile açabiliyorduk. Ancak bu bölümde daha farklı bir şeyden söz edeceğiz. Burada yapacağımız şey, sistemimizde bulunan herhangi bir dosyayı varsayılan uygulamayla açmak değil. Biz burada Python’u kullanarak sistemimizde yeni dosyalar oluşturmanın yanısıra, varolan dosyaları da, herhangi bir aracı program kullanmadan doğrudan Python ile açacağız. Bu ikisi arasındaki farkı biraz sonra daha net bir şekilde göreceksiniz.
Programcılık yaşamınız boyunca dosyalarla bol bol haşır neşir olacaksınız. O yüzden bu bölümü dikkatle takip etmenizi öneririm. İsterseniz lafı hiç uzatmadan konumuza geçelim.
Dosya Oluşturmak¶
Bu bölümde amacımız bilgisayarımızda yeni bir dosya oluşturmak. Anlaması daha kolay olsun diye, Python’la ilk dosyamızı mevcut çalışma dizini altında oluşturacağız. Öncelikle mevcut çalışma dizinimizin ne olduğunu görelim. Hemen Python komut satırını açıyoruz ve şu komutları veriyoruz:
>>> import os
>>> os.getcwd()
Biraz sonra oluşturacağımız dosya bu komutun çıktısı olarak görünen dizin içinde oluşacaktır. Sayın ki bu dizin Masaüstü (Desktop) olsun. Mevcut çalışma dizinimizi de öğrendiğimize göre artık yeni dosyamızı oluşturabiliriz. Bu iş için open() adlı bir fonksiyondan faydalanacağız. Bu fonksiyonu Modüller başlığı altında pyPdf modülünü anlatırken de gördüğümüzü hatırlıyorsunuz...
Bu arada bir yanlış anlaşılma olmaması için hemen belirtelim. Bu fonksiyonu kullanmak için os modülünün içe aktarılmasına gerek yok. Biraz önce os modülünü içe aktarmamızın nedeni yalnızca getcwd() fonksiyonunu kullanmaktı. Bu noktayı da belirttikten sonra komutumuzu veriyoruz:
>>> open("deneme_metni.txt", "w")
Böylelikle masaüstünde deneme_metni.txt adlı bir metin dosyası oluşturmuş olduk. Şimdi verdiğimiz bu komutu biraz inceleyelim. open() fonksiyonunun ne olduğu belli. Bir dosyayı açmaya yarıyor. Tabii ortada henüz bir dosya olmadığı için burada açmak yerine yeni bir dosya oluşturmaya yaradı. Parantez içindeki deneme_metni.txt‘nin de ne olduğu açık. Oluşturacağımız dosyanın adını tırnak içine almayı unutmuyoruz. Peki, bu “w” ne oluyor?
Python’da dosyaları yönetirken, dosya izinlerini de belirtmemiz gerekir. Yani mesela bir dosyaya yazabilmek için “w” kipini (mode) kullanıyoruz. Bu harf İngilizce’de “yazma” anlamına gelen “write” kelimesinin kısaltmasıdır. Bunun dışında bir de “r” kipi ve “a” kipi bulunur. “r”, İngilizce’de “okuma” anlamına gelen “read” kelimesinin kısaltması. “r” kipi, oluşturulan veya açılan bir dosyaya yalnızca “okuma” izni verildiğini gösterir. Yani bu dosya üzerinde herhangi bir değişiklik yapılamaz. Değişiklik yapabilmek için biraz önce gösterdiğimiz “w” kipini kullanmak gerekir. Bir de “a” kipi vardır, dedik. “a” da İngilizce’de “eklemek” anlamına gelen “append” kelimesinden geliyor. “a” kipi önceden oluşturduğumuz bir dosyaya yeni veri eklemek için kullanılır. Bu şu anlama geliyor. Örneğin deneme_metni.txt adlı dosyayı “w” kipinde oluşturup içine bir şeyler yazdıktan sonra tekrar bu kiple açıp içine bir şeyler eklemek istersek dosya içindeki eski verilerin kaybolduğunu görürüz. Çünkü “w” kipi, aynı dosyadan bilgisayarınızda zaten var olup olmadığına bakmaksızın, aynı adda yepyeni bir dosya oluşturacak, bunu yaparken de eski dosyayı silecektir. Dolayısıyla dosya içindeki eski verileri koruyup bu dosyaya yeni veriler eklemek istiyorsak “a” kipini kullanmamız gerekecek. Bu kiplerin hepsini sırası geldiğinde göreceğiz. Şimdi tekrar konumuza dönelim.
Biraz önce;
>>> open("deneme_metni.txt", "w")
komutuyla deneme_metni.txt adında, yazma yetkisi verilmiş bir dosya oluşturduk masaüstünde. Bu komutu bir değişkene atamak, kullanım kolaylığı açısından epey faydalı olacaktır. Biz de şimdi bu işlemi yapalım:
>>> ilkdosyam = open("deneme_metni.txt", "w")
Bu arada dikkatli olun, dediğimiz gibi, eğer bilgisayarınızda önceden deneme_metni.txt adlı bir dosya varsa, yukarıdaki komut size hiç bir uyarı vermeden eski dosyayı silip üzerine yazacaktır.
Şimdi başka bir örnek verelim:
>>> ilkdosyam = open("eski_dosya.txt", "r")
Dikkat ederseniz burada “w” kipi yerine “r” kipini kullandık. Biraz önce de açıkladığımız gibi bu kip dosyaya okuma yetkisi verildiğini gösteriyor. Yani eğer biz bir dosyayı bu kipte açarsak dosya içine herhangi bir veri girişi yapma imkânımız olmaz. Ayrıca bu kip yardımıyla yeni bir dosya da oluşturamayız. Bu kip bize varolan bir dosyayı açma imkânı verir. Yani mesela:
>>> ikincidosyam = open("deneme.txt", "r")
komutunu verdiğimizde eğer bilgisayarda deneme.txt adlı bir dosya yoksa bu adla yeni bir dosya oluşturulmayacak, bunun yerine Python bize bir hata mesajı gösterecektir:
>>> f = open("deneme.txt")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory: 'deneme.txt'
Burada gördüğümüz hata mesajı önemlidir. IOError adlı bu hata mesajı yardımıyla, herhangi bir dosyanın sistemde var olup olmadığını denetleyebiliriz. Mesela şu basit programa bir bakalım:
#!/usr/bin/env python
# -*- coding: cp1254 -*-
import sys
def programdan_cik():
print "Programdan çıkılıyor!"
print "Hoşçakalın..."
sys.exit()
while True:
dosya_adi = raw_input("Açılacak dosyanın adını girin: ")
if dosya_adi:
try:
f = open(dosya_adi, "r")
print "dosya bulundu"
except IOError:
print "Dosya bulunamadı!"
programdan_cik()
else:
print "dosya adı belirtmediniz!"
Burada kullanıcıdan, açılacak dosyanın adını alıyoruz. Kullanıcının, sistemde var olmayan bir dosya adı belirtmesi ihtimaline karşı da try... except bloklarından yararlanıyoruz. Eğer kullanıcının verdiği dosya adı geçerliyse, programımız dosya bulundu çıktısı vererek programı sonlandırıyor. Ama eğer belirtilen dosya bulunamazsa kullanıcı dosyanın bulunamadığı konusunda uyarılıyor ve kendisinden yeni bir dosya adı girmesi isteniyor. Elbette isterseniz, dosyanın bulunamaması durumunda o adla yeni bir dosya oluşturulmasını da sağlayabilirsiniz:
#!/usr/bin/env python
# -*- coding: cp1254 -*-
import sys
def programdan_cik():
print "Programdan çıkılıyor!"
print "Hoşçakalın..."
sys.exit()
while True:
dosya_adi = raw_input("Açılacak dosyanın adını girin: ")
if dosya_adi:
try:
f = open(dosya_adi, "r")
print "dosya bulundu"
except IOError:
print "Dosya bulunamadı!"
open(dosya_adi, "w")
print "%s adlı yeni bir dosya oluşturuldu." %dosya_adi
programdan_cik()
else:
print "dosya adı belirtmediniz!"
Yukarıdaki örneklerde, yoktan bir dosya oluşturmayı ve halihazırda sistemimizde bulunan bir dosyayı açmayı öğrendik. Python’da bir dosyayı “r” kipinde açtığımız zaman, o dosyayı yalnızca okuma hakkı elde ediyoruz. Bu kiple açtığımız bir dosya üzerinde herhangi bir değişiklik yapamayız. Eğer bir dosyayı “w” kipinde açarsak, Python belirttiğimiz addaki dosyayı sıfırdan oluşturacak, eğer aynı adla başka bir dosya varsa o dosyanın üzerine yazacaktır. Python’da dosya işlemleri yaparken, içeriği dolu bir dosyayı açıp bu dosyaya eklemeler yapmamız da gerekebilir. İşte böyle durumlar için “a” adlı özel bir kipten yararlanacağız. Bu kipi şöyle kullanıyoruz:
>>> dosya = open("deneme_metni.txt", "a")
Python’da bir dosyayı “a” kipinde açtığımız zaman, o dosyanın içine yeni veriler ekleyebiliriz. Ayrıca “a” kipinin, “r” kipinin aksine bize yeni dosya oluşturma imkânı da verdiğiniz aklımızın bir köşesine not edelim.
Eğer yazdığımız kod içinde yukarıdaki üç kipten hiçbirini kullanmazsak; Python, öntanımlı olarak “r” kipini kullanacaktır. Tabii “r” kipinin yukarıda bahsettiğimiz özelliğinden dolayı, bilgisayarımızda yeni bir dosya oluşturmak istiyorsak, kip belirtmemiz, yani “w” veya “a” kiplerinden birini kullanmamız gerekir. Bu arada, yukarıdaki örneklerde biz dosyamızı mevcut çalışma dizini içinde oluşturduk. Tabii ki siz isterseniz tam yolu belirterek, dosyanızı istediğiniz yerde oluşturabilirsiniz. Mesela:
>>> dosya = open("/home/kullanıcı_adı/deneme.txt","w")
komutu /home/kullanıcı_adı/ dizini altında, yazma yetkisi verilmiş, deneme.txt adlı bir dosya oluşturacaktır. Ayrıca sadece .txt uzantılı dosyalar değil, pek çok farklı dosya tipi de oluşturabilirsiniz. Mesela .odt uzantılı bir dosya oluşturarak dosyanın OpenOffice ile açılmasını sağlayabilirsiniz. Ya da .html uzantılı bir dosya oluşturarak internet tarayıcınızla açılabilecek bir dosya oluşturabilirsiniz.
Yalnız burada küçük bir uyarı yapalım. Yazdığımız kodlarda yol adı belirtirken kullandığımız yatık çizgilerin yönüne dikkat etmemiz gerekir. En emin yol, yukarıda yaptığımız gibi dosya yolunu sağa yatık bölü işaretiyle ayırmaktır:
>>> dosya = open("/home/kullanıcı_adı/deneme.txt","w")
Sağa yatık bölü bütün işletim sistemlerinde sorunsuz çalışır. Ama sola yatık bölü problem yaratabilir:
>>> f = open("C:\Documents and Settings\fozgul\Desktop\filanca.txt", "a")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: [Errno 22] invalid mode ('a') or filename: 'C:\\Documents and Settings\
x0cozgul\\Desktop\x0cilanca.txt'
Burada sorun, Python’un “\” işaretini bir kaçış dizisi olarak algılaması. Halbuki biz burada bu işareti yol ayracı olarak kullanmak istedik... Eğer sağa yatık bölü kullanmak isterseniz “\” işaretini çiftlemeniz gerekir:
>>> f = open("C:\\Documents and Settings\\fozgul\\Desktop\\filanca.txt", "a")
Veya “r” adlı kaçış dizisinden yararlanabilirsiniz:
>>> f = open(r"C:\Documents and Settings\fozgul\Desktop\filanca.txt", "a")
Böylece dosya yolunu oluşturan karakter dizisi içindeki kaçış dizilerini işlevsiz hale getirerek Python’ın hata vermesini engelleyebilirsiniz.
Dosyaya Yazmak¶
Şu ana kadar öğrendiğimiz şey, Python’da dosya açmak ve oluşturmaktan ibarettir. Ancak henüz açtığımız bir dosyaya nasıl müdahale edeceğimizi veya nasıl veri girişi yapabileceğimizi bilmiyoruz. İşte birazdan, bilgisayarımızda halihazırda var olan veya bizim sonradan oluşturduğumuz bir dosyaya nasıl veri girişi yapabileceğimizi göreceğiz. Mesela deneme.txt adlı bir dosya oluşturarak içine “Guido Van Rossum” yazalım. Ama bu kez komut satırında değil de metin üzerinde yapalım bu işlemi. Hemen boş bir sayfa açıp içine şunları yazıyoruz:
#/usr/bin/env python
# -*- coding: utf-8
dosya = open("deneme.txt", "w")
dosya.write("Guido Van Rossum")
dosya.close()
İlk iki satırın ne olduğunu zaten bildiğimiz için geçiyoruz.
Aynen biraz önce gördüğümüz şekilde dosya adlı bir değişken oluşturup bu değişkenin değeri olarak open("deneme.txt", "w") satırını belirledik. Böylelikle deneme.txt adında, yazma yetkisi verilmiş bir dosya oluşturduk. Daha sonra write() adlı bir fonksiyon yardımıyla deneme.txt dosyasının içine “Guido Van Rossum” yazdık. En son da close() adlı başka bir fonksiyondan yararlanarak dosyayı kapattık. Aslında GNU/Linux kullanıcıları bu son dosya.close() satırını yazmasa da olur. Ama özellikle Windows üzerinde çalışırken, eklemelerin dosyaya işlenebilmesi için dosyanın kapatılması gerekiyor. Ayrıca muhtemelen Python’un ileriki sürümlerinde, bütün platformlarda bu satırı yazmak zorunlu olacak. O yüzden bu satırı da yazmak en iyisi. Şimdi de şöyle bir şey yapalım:
Biraz önce oluşturduğumuz ve içine “Guido Van Rossum” yazdığımız dosyamıza ikinci bir satır ekleyelim:
#!/usr/bin/env python
#-*- coding: utf-8
dosya = open("deneme.txt", "a")
dosya.write("\nMonty Python")
dosya.close()
Gördüğünüz gibi bu kez dosyamızı “a” kipiyle açtık. Zaten “w” kipiyle açarsak eski dosyayı silmiş oluruz. O yüzden Python’la programlama yaparken bu tür şeylere çok dikkat etmek gerekir.
Dosyamızı “a” kipiyle açtıktan sonra write() fonksiyonu yardımıyla “Monty Python” satırını eski dosyaya ekledik. Burada “\n” adlı kaçış dizisinden yararlandığımıza da dikkat edin. Eğer bunu kullanmazsak eklemek istediğimiz satır bir önceki satırın hemen arkasına getirilecektir. Bütün bunlardan sonra da close() fonksiyonu yardımıyla dosyamızı kapattık. Bir de şu örneğe bakalım:
#!/usr/bin/env python
#-*- coding: utf-8
dosya = open(u"şiir.txt", "w")
dosya.write("Bütün güneşler batmadan,\nBi türkü daha \
söyleyeyim bu yerde\n\t\t\t\t --Orhan Veli--")
dosya.close()
Gördüğünüz gibi, “şiir” adlı bir metin dosyası oluşturup bu dosyaya yazma yetkisi verdik. Burada bir şey dikkatinizi çekmiş olmalı. Dosya adını belirlerken (şiir.txt) karakter dizisinin başına bir adet “u” harfi getirdik. Siz bu harfi pyPdf modülünü işlerken de görmüştünüz. Bu “u” harfini kullanmamızın amacı, dosya adında geçen Türkçe karakterin düzgün görüntülenmesini sağlamak. Buradaki “u” harfi, “şiir.txt” adlı karakter dizisini Unicode olarak tanımlamamızı sağlıyor. Bu konuyu birkaç bölüm sonra çok daha ayrıntılı bir şekilde inceleyeceğiz. Şimdilik sadece böyle bir şeyin varolduğunu bilmemiz yeterli olacaktır...
Bu dosyanın içine yazılan verilere ve burada kaçış dizilerini nasıl kullandığımıza çok dikkat edin. İkinci mısrayı bir alt satıra almak için “\n” kaçış dizisini kullandık. Daha sonra “Orhan Veli” satırını sayfanın sağına doğru kaydırmak için “\t” kaçış dizisinden yararlandık. Bu örnekte “\n” ve “\t” kaçış dizilerini yan yana kullandık. Böylece aynı cümleyi hem alt satıra almış, hem de sağa doğru kaydırmış olduk. Ayrıca birkaç tane “\t” kaçış dizisini yan yana kullanarak cümleyi sayfanın istediğimiz noktasına getirdik.
Yukarıdaki write() fonksiyonu dışında çok yaygın kullanılmayan bir de writelines() fonksiyonu vardır. Bu fonksiyon birden fazla satırı bir kerede dosyaya işlemek için kullanılır. Şöyle ki:
#!/usr/bin/env python
#-*- coding: utf-8
dosya = open(u"şiir2.txt", "w")
dosya.writelines(["Bilmezler yalnız yaşamayanlar\n",
"Nasıl korku verir sessizlik insana\n",
"İnsan nasıl konuşur kendisiyle\n",
"Nasıl koşar aynalara bir cana hasret\n",
"Bilmezler...\n"])
dosya.close()
Burada parantez içindeki köşeli parantezlere dikkat edin. Aslında oluşturduğumuz şey bir liste. Dolayısıyla bu fonksiyon bir listenin içeriğini doğrudan bir dosyaya yazdırmak için faydalı olabilir. Aynı kodu write() fonksiyonuyla yazmaya kalkışırsanız alacağınız şey bir hata mesajı olacaktır. Eğer bir liste içinde yer alan öğeleri write() fonksiyonunu kullanarak dosyaya yazdırmak isterseniz for döngüsünden yararlanabilirsiniz:
>>> liste = ["elma", "armut", "kalem"]
>>> f = open("falanca.txt", "w")
>>> for i in liste:
... f.write(i+"\n")
...
>>> f.close()
Dosyayı Okumak¶
Şimdiye kadar nasıl yeni bir dosya oluşturacağımızı, bu dosyaya nasıl veri gireceğimizi ve bu dosyayı nasıl kapatacağımızı öğrendik. Şimdi de oluşturduğumuz bir dosyadan nasıl veri okuyacağımızı öğreneceğiz. Bu iş için de read(), readlines() ve readline() fonksiyonlarından faydalanacağız. Şu örneğe bir bakalım:
>>> yeni = open(u"şiir.txt","w")
>>> yeni.write("Sular çekilmeye başladı \
... köklerden...\nIsınmaz mı acaba ellerimde kan? \
... \nAh,ne olur! Bütün güneşler batmadan\nBi türkü \
... daha söyleyeyim bu yerde...")
>>> yeni.close()
>>> yeni=open(u"şiir.txt")
>>> yeni.read()
'Sular \xc3\xa7ekilmeye ba\xc5\x9flad\xc4\xb1 k\xc3\xb6klerden...
\nIs\xc4\xb1nmaz m\xc4\xb1 acaba ellerimde kan? \nAh,ne olur!
B\xc3\xbct\xc3\xbcn g\xc3\xbcne\xc5\x9fler batmadan \nBi
t\xc3\xbcrk\xc3\xbc daha s\xc3\xb6yleyeyim bu yerde...'
yeni.read() satırına kadar olan kısmı zaten biliyoruz. Burada kullandığımız read() fonksiyonu yeni adlı değişkenin içeriğini okumamızı sağlıyor. yeni adlı değişkenin değeri şiir.txt adlı bir dosya olduğu için, bu fonksiyon şiir.txt adlı dosyanın içeriğini bize gösterecektir. Gördüğünüz gibi bu komutun çıktısında Türkçe karakterler bozuk görünüyor. Ayrıca kullandığımız “\n” ifadesi de çıktıda yer alıyor. Esasında bu komut bize Python’un yazdığımız kodları nasıl gördüğünü gösteriyor. Eğer biz daha düzgün bir çıktı elde etmek istersek en son satırdaki komutu şu şekilde vermemiz gerekir:
>>> print yeni.read()
Ayrıca read() dışında bir de readlines() adlı bir fonksiyon bulunur. Eğer yukarıdaki komutu:
>>> yeni.readlines()
şeklinde verecek olursak, çıktının bir liste olduğunu görürüz.
Bir de, eğer bu readlines() fonksiyonunun sonundaki “s” harfini atıp;
>>> yeni.readline()
şeklinde bir kod yazarsak, dosya içeriğinin yalnızca ilk satırı okunacaktır. Python’un readline() fonksiyonunu değerlendirirken kullandığı ölçüt şudur: “Dosyanın başından itibaren ilk ‘\n’ ifadesini gördüğün yere kadar oku”. Bunların dışında, eğer istersek bir for döngüsü kurarak da dosyamızı okuyabiliriz:
>>> yeni = open(u"şiir.txt")
>>> for satir in yeni:
... print satir
Dikkat ettiyseniz:
>>> print yeni.readlines()
veya alternatif komutlarla dosya içeriğini okurken şöyle bir şey oluyor. Mesela içinde;
Birinci satır
İkinci satır
Üçüncü satır
yazan bir dosyamız olsun:
>>> dosya.readline()
komutuyla bu dosyanın ilk satırını okuyalım. Daha sonra tekrar bu komutu verdiğimizde birinci satırın değil, ikinci satırın okunduğunu görürüz. Çünkü Python ilk okumadan sonra imleci (Evet, biz görmesek de aslında Python’un dosya içinde gezdirdiği bir imleç var.) dosyada ikinci satırın başına kaydırıyor. Eğer bir daha verirsek bu komutu, üçüncü satır okunacaktır. Son bir kez daha bu komutu verirsek, artık dosyanın sonuna ulaşıldığı için, ekrana hiç bir şey yazılmayacaktır. Böyle bir durumda dosyayı başa sarmak için şu fonksiyonu kullanıyoruz. (Dosyamızın adının “dosya” olduğunu varsayıyoruz):
>>> dosya.seek(0)
Böylece imleci tekrar dosyanın en başına almış olduk. Tabii siz isterseniz, bu imleci farklı noktalara da taşıyabilirsiniz. Mesela:
>>> dosya.seek(10)
komutu imleci 10. karakterin başına getirecektir (Saymaya her zamanki gibi 0’dan başlıyoruz.) Bu seek() fonksiyonu aslında iki adet parametre alabiliyor. Şöyle ki:
>>> dosya.seek(5, 0)
komutu imleci dosyanın başından itibaren 5. karakterin bulunduğu noktaya getirir. Burada “5” sayısı imlecin kaydırılacağı noktayı, “0” sayısı ise bu işlemin dosyanın başından sonuna doğru olacağını, yani saymaya dosyanın başından başlanacağını gösteriyor:
>>> dosya.seek(5, 1)
komutu imlecin o anda bulunduğu konumdan itibaren 5. karakterin olduğu yere ilerlemesini sağlar. Burada “5” sayısı yine imlecin kaydırılacağı noktayı, “1” sayısı ise imlecin o anda bulunduğu konumun ölçüt alınacağını gösteriyor.
Son olarak:
>>> dosya.seek(-5,2)
komutu ise saymaya tersten başlanacağını, yani dosyanın başından sonuna doğru değil de sonundan başına doğru ilerlenerek, imlecin sondan 5. karakterin olduğu yere getirileceğini gösterir.
Bu ifadeler biraz karışık gelmiş olabilir. Bu konuyu anlamanın en iyi yolu bol bol uygulama yapmak ve deneyerek görmektir. İsterseniz, yukarıdaki okuma fonksiyonlarına da belirli parametreler vererek dosya içinde okunacak satırları veya karakterleri belirleyebilirsiniz. Mesela:
>>> yeni.readlines(3)
komutu dosya içinde, imlecin o anda bulunduğu noktadan itibaren 3. karakterden sonrasını okuyacaktır. Peki, o anda imlecin hangi noktada olduğunu nereden bileceğiz? Python’da bu işlem için de bir fonksiyon bulunur:
>>> dosya.tell()
komutu yardımıyla imlecin o anda hangi noktada bulunduğunu görebilirsiniz. Hatta dosyayı bir kez:
>>> dosya.read()
komutuyla tamamen okuttuktan sonra:
>>> dosya.tell()
komutunu verirseniz imleç mevcut dosyanın en sonuna geleceği için, ekranda gördüğünüz sayı aynı zamanda mevcut dosyadaki karakter sayısına eşit olacaktır.
Python’da dosya işlemleri yaparken bilmemiz gereken en önemli noktalardan biri de şudur: Python ancak karakter dizilerini (strings) dosyaya yazdırabilir. Sayıları yazdıramaz. Eğer biz sayıları da yazdırmak istiyorsak önce bu sayıları karakter dizisine çevirmemiz gerekir. Bir örnek verelim:
>>> x = 50
>>> dosya = open("deneme.txt", "w")
>>> dosya.write(x)
Bu kodlar bize şu çıktıyı verir:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: argument 1 must be string
or read-only character buffer, not int
Gördüğünüz gibi Python bize bir hata mesajı gösterdi. Çünkü x değişkeninin değeri bir “sayı”. Halbuki karakter dizisi olması gerekiyor. Bu meseleyi çözmek için komutumuzu şu şekilde veriyoruz. En baştan alırsak:
>>> x = 50
>>> dosya = open("deneme.txt", "w")
>>> dosya.write(str(x))
Burada:
>>> str(x)
komutuyla, bir sayı olan x değişkenini karakter dizisine çevirdik. Tabii ki bu işlemin tersi de mümkün. Eğer x bir karakter dizisi olsaydı, şu komutla onu sayıya çevirebilirdik:
>>> int(x)
Dosya Silmek¶
Peki, oluşturduğumuz bu dosyaları nasıl sileceğiz? Python’da herhangi bir şekilde oluşturduğumuz bir dosyayı silmenin en kestirme yolu şudur:
>>> os.remove("dosya/yolu")
Mesela, masaüstündeki deneme.txt dosyasını şöyle siliyoruz:
>>> import os
>>> os.remove("/home/kullanıcı_adı/Desktop/deneme.txt")
Eğer masaüstü zaten sizin mevcut çalışma dizininiz ise bu işlem çok daha basittir:
>>> import os
>>> os.remove("deneme.txt")
Dosyaya Rastgele Satır Eklemek¶
Şimdiye kadar hep dosya sonuna satır ekledik. Peki ya bir dosyanın ortasına bir yere satır eklemek istersek ne yapacağız? Şimdi: Diyelim ki elimizde deneme.txt adlı bir dosya var ve içinde şunlar yazılı:
Birinci Satır
İkinci Satır
Üçüncü Satır
Dördüncü Satır
Beşinci Satır
Biz burada İkinci Satır ile Üçüncü Satır arasına Merhaba Python! yazmak istiyoruz. Önce bu deneme.txt adlı dosyayı açalım:
>>> kaynak = open("deneme.txt")
Bu dosyayı “okuma” kipinde açtık, çünkü bu dosyaya herhangi bir yazma işlemi yapmayacağız. Yapacağımız şey, bu dosyadan veri okuyup başka bir hedef dosyaya yazmak olacak. O yüzden hemen bu hedef dosyamızı oluşturalım:
>>> hedef = open("test.txt", "w")
Bu dosyayı ise “yazma” modunda açtık. Çünkü kaynak dosyadan okuduğumuz verileri buraya yazdıracağız. Şimdi de, yapacağımız okuma işlemini tanımlayalım:
>>> oku = kaynak.readlines()
Böylece “kaynak” dosya üzerinde yapacağımız satır okuma işlemini de tanımlamış olduk...
Şimdi kaynak dosyadaki birinci satır ve ikinci satır verilerini alıp hedef dosyaya yazdırıyoruz. Bu iş için bir for döngüsü oluşturacağız:
>>> for satirlar in oku[:2]:
... hedef.write(satirlar)
Burada biraz önce oluşturduğumuz “okuma işlemi” değişkeni yardımıyla “0” ve “1” no’lu satırları alıp hedef adlı dosyaya yazdırdık. Şimdi eklemek istediğimiz satır olan Merhaba Python! satırını ekleyeceğiz:
>>> hedef.write("Merhaba Python!\n")
Sıra geldi kaynak dosyada kalan satırları hedef dosyasına eklemeye:
>>> for satirlar in oku[2:]:
... hedef.write(satirlar)
Artık işimiz bittiğine göre hedef ve kaynak dosyaları kapatalım:
>>> kaynak.close()
>>> hedef.close()
Bu noktadan sonra eğer istersek kaynak dosyayı silip adını da hedef dosyanın adıyla değiştirebiliriz:
>>> os.remove("deneme.txt")
>>> os.rename("test.txt","deneme.txt")
Tabii bu son işlemleri yapmadan önce os modülünü içe aktarmayı unutmuyoruz...
Yukarıdaki işlemleri yapmanın daha pratik bir yolu da var. Diyelim ki elimizde, içeriği şu olan falanca.xml adlı bir dosya var:
<EnclosingTag>
<Fierce name="Item1" separator="," src="myfile1.csv" />
<Fierce name="Item2" separator="," src="myfile2.csv" />
<Fierce name="Item3" separator="," src="myfile3.csv" />
<Fierce name="Item4" separator="," src="myfile4.csv" />
<Fierce name="Item5" separator="," src="myfile5.csv" />
<NotFierce Name="Item22">
</NotFierce>
</EnclosingTag>
Not
Bu dosya içeriği http://www.python-forum.org/pythonforum/viewtopic.php?f=1&t=19641 adresinden alınmıştır.
Biz bu dosyada, “Item2” ile “Item3” arasına yeni bir satır eklemek istiyoruz. Dilerseniz bu işlemi nasıl yapacağımızı gösteren kodları verelim önce:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
oku = open("falanca.xml")
eklenecek_satir = '<Fierce name="Item2.5" separator="," src="myfile25.csv" />'
icerik = oku.readlines()
icerik.insert(4, eklenecek_satir+"\n")
oku.close()
yaz = open("falanca.xml", "w")
yaz.writelines(icerik)
yaz.close()
Şimdi de bu kodları tek tek inceleyelim:
- oku = open("falanca.xml") satırı yardımıyla falanca.xml adlı dosyayı okumak üzere açıyoruz.
- Daha sonra, dosyaya eklemek istediğimiz satırı bir değişkene atıyoruz.
- Hemen ardından readlines() adlı metodu kullanarak falanca.xml adlı dosyanın tüm içeriğini bir liste içinde topluyoruz. Böylece dosya içeriğini yönetmek çok daha kolay olacak. Bildiğiniz gibi, readlines() metodu bize çıktı olarak bir liste veriyor...
- Bir sonraki satırda, dosyaya eklemek istediğimiz metni, readlines() metodu ile oluşturduğumuz listenin 4. sırasına yerleştiriyoruz. Burada listelerin insert() metodunu kullandığımıza dikkat edin.
- Artık dosyayı okuma işlemi sona erdiği için dosyamızı close() metodunu kullanarak kapatıyoruz.
- Şimdi yapmamız gereken şey, gerekli bilgileri dosyaya yazmak olacak. O yüzden bu defa falanca.xml adlı dosyayı yazma kipinde açıyoruz. (yaz = open("falanca.xml", "w"))
- Sonra, yukarıda oluşturduğumuz içeriği, yazmak üzere açtığımız dosyaya gönderiyoruz. Bunun için writelines() metodunu kullandık. Bildiğiniz gibi bu metot listeleri dosyaya yazdırmak için kullanılıyor.
- Son olarak, dosyayla işimizi bitirdiğimize göre dosyamızı kapatmayı unutmuyoruz.
Dosyadan Rastgele Satır Silmek¶
Bazen, üzerinde çalıştığımız bir dosyanın herhangi bir satırını silmemiz de gerekebilir. Bunun için yine bir önceki bölümde anlattığımız yöntemi kullanabiliriz. Dilerseniz gene yukarıda bahsettiğimiz .xml dosyasını örnek alalım:
<EnclosingTag>
<Fierce name="Item1" separator="," src="myfile1.csv" />
<Fierce name="Item2" separator="," src="myfile2.csv" />
<Fierce name="Item3" separator="," src="myfile3.csv" />
<Fierce name="Item4" separator="," src="myfile4.csv" />
<Fierce name="Item5" separator="," src="myfile5.csv" />
<NotFierce Name="Item22">
</NotFierce>
</EnclosingTag>
Şimdi diyelim ki biz bu dosyanın “Item2” satırını silmek istiyoruz. Bu işlemi şu kodlarla halledebiliriz:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
oku = open("write_it.xml")
icerik = oku.readlines()
del icerik[3]
oku.close()
yaz = open("write_it.xml", "w")
yaz.writelines(icerik)
yaz.close()
Burada da, tıpkı bir önceki bölümde olduğu gibi, öncelikle readlines() metodunu kullanarak dosya içeriğini bir listeye gönderdik. Daha sonra bu listede silmek istediğimiz satıra karşılık gelen öğenin sıra numarasını kullanarak del deyimi yardımıyla ilgili öğeyi listeden kaldırdık. Son olarak da elimizdeki değiştirilmiş listeyi bir dosyaya yazdırdık.
Gördüğünüz gibi bir dosyaya veri girmek veya dosyadan veri çıkarmak son derecek kolay bir işlem. Yapmamız gereken tek şey dosya içeriğini bir listeye alıp, bu liste üzerinde gerekli değişiklikleri yapmak. Daha sonra da bu değiştirilmiş listeyi dosyaya yazdırararak amacımıza ulaşabiliyoruz.
os Modülünde Dosya-Dizin İşlemleri¶
Hatırlarsanız geçen bölümde Modüller konusunu işlerken os modülünden de ayrıntılı olarak bahsetmiştik. Ancak orada bu modülün bütün özelliklerini anlatmadım. os modülünün bazı özelliklerini anlatabilmek için önce “Dosya İşlemleri” konusunu öğrenmemizin daha doğru olacağını düşündüm. Dosya işlemleri konusunu öğrendiğimize göre, geçen derste bahsetmediğimiz bazı metot ve fonksiyonları incelemeye başlayabiliriz.
os.path.abspath()¶
Bu metot bir dosyanın, içinde yer aldığı dizin yolunu verir. Bunu bir örnek üzerinde görelim:
>>> os.path.abspath("falanca.pdf")
'C:\\Documents and Settings\\fozgul\\falanca.pdf'
Gördüğünüz gibi, os.path.abspath() fonksiyonuna argüman olarak bir dosya adı verdik. O da bize bu dosyanın tam yolunu gösterdi. Ancak bu fonksiyonun önemli bir özelliği vardır. os.path.abspath(), bir dosyanın sistemde var olup olmadığını kontrol etmez. Yani os.path.abspath("falanca.pdf") komutunu verebilmek için sisteminizde falanca.pdf adlı bir dosyanın olmasına gerek yok. Bu fonksiyonun yaptığı tek şey, os.getcwd() fonksiyonunun çıktısıyla, verdiğiniz dosya adını birleştirmektir... Bu fonksiyonu boş bir karakter dizisi ile çağırdığınızda zaten bu fonksiyonun mevcut çalışma dizinini döndürdüğünü görürsünüz:
>>> os.path.abspath("")
'C:\\Documents and Settings\\fozgul'
os.path.basename()¶
Bu metot size bir yol içinde yer alan dosyanın adını verir. Örneğin:
>>> os.path.basename("C:\\Documents and Settings\\fozgul\\falanca.pdf")
'falanca.pdf'
Gördüğünüz gibi, bu metot yol ve dosya adını ayıklayarak, bize dosya adını veriyor.
os.path.dirname()¶
Bu metot ise bir önceki metodun yaptığı işin tam tersini yapar: Dosya adını değil, yol adını döndürür:
>>> os.path.dirname("C:\\Documents and Settings\\fozgul\\falanca.pdf")
'C:\\Documents and Settings\\fozgul'
os.path.exists()¶
Bu metot bir dosyanın veya dizinin var olup olmadığını gösterir:
>>> os.path.exists("C:\\Documents and Settings\\fozgul\\falanca.pdf")
False
>>> os.path.exists("C:\\Documents and Settings\\fozgul")
True
os.path.isdir()¶
Bu metot, verilen bir yolun dizin olup olmadığını kontrol eder:
>>> os.path.isdir("C:\\Documents and Settings\\fozgul\\falanca.pdf")
False
falanca.pdf bir dizin olmadığı için False çıktısı aldık:
>>> os.path.isdir("C:\\Documents and Settings\\fozgul")
True
C:\Documents and Settings\fozgul ise bir dizin olduğu için True çıktısı aldık.
os.path.isdir() metodu, aynı zamanda bir dizinin var olup olmadığını da kontrol eder:
>>> os.path.isdir("C:\\falanca\\dizin")
False
Bilgisayarımızda C:\falanca\dizin adlı bir dizin var olmadığı için False çıktısı alıyoruz...
os.path.isfile()¶
Bu metot, verilen bir yolun dosya olup olmadığını kontrol eder:
>>> os.path.file("C:\\Documents and Settings\\fozgul\\deneme.txt")
True
Benim bilgisayarımda deneme.txt adlı bir dosya olduğu için True çıktısı aldım.
Bir de şuna bakalım:
>>> os.path.file("C:\\Documents and Settings\\fozgul\\falanca.txt")
False
Bilgisayarımda falanca.txt adlı bir dosya yer almadığı için bu kez False çıktısı aldım.
Bu metot dosya ve dizinler arasında da ayrım yapar:
>>> os.path.isfile("C:\\Documents and Settings\\fozgul")
False
C:\Documents and Settings\fozgul bir dosya değil, ama dizin adı olduğu için isfile() metodu False çıktısı veriyor.
os.path.split()¶
Bu metot, dosya ve dizin adını birbirinden ayırır:
>>> os.path.split("C:\\Documents and Settings\\fozgul\\falanca.pdf")
('C:\\Documents and Settings\\fozgul', 'falanca.pdf')
Dolayısıyla şu komut size bir dosyanın, içinde yer aldığı dizini gösterecektir:
>>> yol = os.path.split("C:\\Documents and Settings\\fozgul\\falanca.pdf")
>>> yol[0]
'C:\\Documents and Settings\\fozgul'
Şu ise size dosya adını verecektir:
>>> yol = os.path.split("C:\\Documents and Settings\\fozgul\\falanca.pdf")
>>> yol[1]
'falanca.pdf'
Bu metot da bir dosya ya da dizinin sistemde var olup olmadığına bakmaz...
os.path.splitext()¶
Bu metot, bir dosya adıyla uzantısını birbirinden ayırır:
>>> os.path.splitext("falanca.pdf")
('falanca', '.pdf')
Kümeler ve Dosyalar¶
Önceki bölümlerden birinde kümelerden bahsetmiştik. Kümeleri ilk gördüğünüzde bunların tam olarak ne işe yarayacağını anlamamış olabilirsiniz. Ama aslında kümeler Python’un epey kullanışlı araçlarından bir tanesidir. Biz kümeleri dosya işlemleri yaparken dahi kullanabiliriz.
Hatırlarsanız, kümeleri işlerken birtakım metotlardan söz etmiştik. Bildiğiniz gibi kümeler şu metotlara sahipti:
add
clear
copy
difference
difference_update
discard
intersection
intersection_update
isdisjoint
issubset
issuperset
pop
remove
symmetric_difference
symmetric_difference_update
union
update
Bu metotlar içinde özellikle iki tanesi, dosyalarla çalışırken bizim çok işimize yarayacak. Bahsettiğimiz bu metotlar difference() ve intersection() adlı metotlardır.
Bildiğiniz gibi, difference() metodu iki kümenin farkını alıyor. Bu metodu şöyle kullanıyoruz:
>>> a_kumesi = set([1, 2, 3])
>>> b_kumesi = set([1, 2, 3, 4])
>>> b_kumesi.difference(a_kumesi)
set([4])
Demek ki b kümesinin a kümesinden farkı 4 adlı öğe imiş... Bu metodu dosyalara da uygulayabiliriz. Diyelim ki elimizde şöyle iki adet dosya var:
birinci satır
ikinci satır
üçüncü satır
Yukarıdaki dosya1.txt olsun. Bir de dosya2.txt adlı bir dosya oluşturalım:
birinci satır
ikinci satır
üçüncü satır
dördüncü satır
Bu iki dosyanın farkını almak, yani mesela ikinci dosyada bulunup birinci dosyada bulunmayan satırları göstermek için şöyle bir kod yazabiliriz:
>>> f1 = open("dosya1.txt")
>>> f2 = open("dosya2.txt")
>>> s1 = set(f1)
>>> s2 = set(f2)
>>> for i in s2.difference(s1):
... print i
dördüncü satır
Aynı şekilde, intersection() metodunu kullanarak da iki dosyada ortak olan satırları bulabilirsiniz:
>>> for i in s1.intersection(s2):
... print i
birinci satır
ikinci satır
üçüncü satır
with Deyimi¶
Dosyalarla çalışırken asla unutmamamız gereken şey, işimizi bitirdikten sonra dosyayı kapatmaktır. Çünkü eğer bir dosya üzerinde çalıştıktan sonra o dosyayı kapatmazsak, yaptığımız değişikliklerin hepsi dosyaya işlenmeyebilir. O yüzden bu tür durumları önlemek için açılan dosyayı işlem sonunda kapatmamız gerekir. Ayrıca dosyayı kapatmak, açık bir dosya üzerinde yanlışlıkla değişiklik yapma riskini de ortadan kaldırır.
Normal şartlar altında bir dosya üzerinde çalışma döngüsü şöyle işler:
>>> dosya = open("dosya_adı", "w")
>>> dosya.write("bir takım şeyler...")
>>> dosya.close()
Burada şöyle bir yol izliyoruz:
- Dosyayı açıyoruz.
- Dosya üzerinde gerekli değişiklikleri yapıyoruz.
- İşimiz bitince dosyayı kapatıyoruz.
Python’da bu döngüyü daha pratik bir şekilde yapmamızı sağlayan bir deyim bulunur. Bu deyim, with deyimidir. with deyimini yukarıdaki şöyle uygulayabiliriz:
>>> with open("dosya_adı", "w") as dosya:
... dosya.write("bir takım şeyler...")
Bu iki satırlık kod sayesinde dosyamızı hem açmış, hem üzerinde gerekli değişiklikleri yapmış, hem de dosyayı kapatmış olduk.
with deyiminin en önemli özelliği, açılan dosyayı mutlaka kapatmasıdır. Yani dosya üzerinde işlem yapılırken bir hata da oluşsa o dosya başarıyla kapatılacaktır. Bu durumu daha net anlamak için şöyle bir örnek verelim:
>>> dosya = open("falanca")
>>> dosya.write("bir takım şeyler...")
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
IOError: File not open for writing
>>> dosya
<open file 'write_it.xml', mode 'r' at 0x00F5B650>
Gördüğünüz gibi, dosyayı yazma kipinde açmadığımız için dosyaya veri yazdırmamız mümkün olmuyor. Böyle bir durumda Python bize bir hata mesajı gösteriyor. Ancak bu hata mesajından sonra, dosyayı henüz kapatmadığımız için dosyamız hala açık. Bu durumu dosya değişkenini ekrana yazdırarak teyit ettik. Dosya açık olduğu için üzerinde işlem yapmaya devam edebiliriz:
>>> dosya.read()
'varolan içerik...'
Bir de şuna bakalım:
>>> with open("falanca") as dosya:
... dosya.write("bir takım şeyler...")
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
IOError: File not open for writing
>>> dosya
<closed file 'write_it.xml', mode 'r' at 0x00F5B5A0>
Gördüğünüz gibi, dosyaya yazma işlemi sırasında hata aldığımız halde, dosya her şeye rağmen kapanıyor. Artık dosya üzerinde herhangi bir işlem yapmamız mümkün değil:
>>> dosya.read()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file
Python bizi, kapalı bir dosya üzerinde işlem yapmaya çalıştığımız konusunda nazikçe uyarıyor...
Bölüm Soruları¶
1. Python yardımıyla, içeriği ve görünüşü aşağıdaki gibi olan, istihza.html adlı bir belge oluşturun:
istihza.com Hakkında
istihza.com, Python programlama dili ve Tkinter için bir Türkçe kaynak oluşturma çalışmasıdır. Burada aynı zamanda PyGTK adlı arayüz takımına ilişkin Türkçe bilgi de verilmektedir. Günlük ise konu çeşitliliği açısından daha esnek bir bölüm olarak tasarlandı... Günlük bölümünden, bu siteye ilişkin son gelişmeler ve duyurular hakkında ayrıntılı bilgiye de erişebilirsiniz.
2. Kullanıcıdan aldığı birtakım bilgiler doğrultusunda anlamlı bir paragraf oluşturabilen bir program yazın. Oluşturduğunuz bu paragrafı daha sonra .html uzantılı bir dosya halinde kaydedip, sistemdeki öntanımlı internet tarayıcısı yardımıyla kullanıcıya gösterin.
3. Python ile oluşturduğunuz veya açtığınız herhangi bir dosyayla işiniz bittikten sonra eğer bu dosyayı close() fonksiyonu ile kapatmazsanız ne gibi sonuçlarla karşılaşırsınız? Açtığınız dosyayı kapatmadan, varolan dosyayı sağ tık > sil yolunu takip ederek silmeye çalıştığınızda işletim sisteminiz nasıl bir tepki veriyor?
4. os.path.abspath() fonksiyonunun yaptığı işi taklit eden bir fonksiyon yazın.
5. Bir PDF belgesinin herhangi bir sayfasını kesip ayrı bir PDF belgesi oluşturan bir program yazın. Bu program sadece PDF belgeleri üzerinde işlem yapmalı. Eğer kullanıcı PDF dışı bir dosya adı belirtirse, programınız dosyanın PDF biçiminde olmadığı konusunda kullanıcıyı uyarmalı.
6. Bir dosyada belli bir satırın olup olmamasına göre işlem yapan bir program yazın. Mesela yazdığınız program bir dosyaya bakıp içinde o satırın geçip geçmediğini tespit edebilmeli. Eğer ilgili satır dosyada yoksa o satırı dosyaya eklemeli, aksi halde herhangi bir işlem yapmadan programı sonlandırmalı.