7. Metin dosyaları

7.1. [fic_01] komut dosyası: bir metin dosyasını okuma / yazma
Aşağıdaki komut dosyası, metin dosyalarının kullanımına ilişkin bir örneği göstermektedir:
# ithalatlar
import sys
# bir metin dosyasının oluşturulması ve ardından sıralı olarak işlenmesi
# bu dosya, login:pwd:uid:gid:infos:dir:shell biçiminde satırlardan oluşur
# her satır, "login => uid:gid:infos:dir:shell" biçiminde bir sözlüğe eklenir
# --------------------------------------------------------------------------
def affiche_infos(dico: dict, clé: str):
# dico sözlüğünde anahtara ait değer varsa bunu görüntüler
if clé in dico.keys():
# anahtara atanan değer görüntülenir
print(f"{clé} : {dico[clé]}")
else:
# anahtar, dico sözlüğünde bulunmuyor
print(f"la clé [{clé}] n'existe pas")
# main -----------------------------------------------
# dosya adı belirlenir
FILE_NAME = "./data/infos.txt"
# metin dosyasının oluşturulması ve doldurulması
fic = None
try:
# dosyanın yazma modunda açılması (w=write)
fic = open(FILE_NAME, "w")
# rastgele içerik oluşturulur
for i in range(1, 101):
# bir satır
ligne = f"login{i}:pwd{i}:uid{i}:gid{i}:infos{i}:dir{i}:shell{i}"
# metin dosyasına yazılır
fic.write(f"{ligne}\n")
except IOError as erreur:
print(f"Erreur d'exploitation du fichier {FILE_NAME} : {erreur}")
sys.exit()
finally:
# dosya açılmışsa kapatılır
if fic:
fic.close()
# dosya okuma modunda açılır
fic = None
try:
# dosya okuma modunda açılır
fic = open(FILE_NAME, "r")
# başlangıçta boş sözlük
dico = {}
# her satır, [dico] sözlüğüne login => uid:gid:infos:dir:shell biçiminde eklenir
# satır başı ve sonundaki boşluklar kaldırılarak ilk satır okunuyor
ligne = fic.readline().strip()
# satır boş olmadığı sürece
while ligne != '':
# satırı bir diziye ekliyoruz
infos = ligne.split(":")
# kullanıcı adını alıyoruz
login = infos[0]
# şifreyi göz ardı edilir
infos[0:2] = []
# sözlüğe bir giriş oluşturulur
dico[login] = infos
# bir sonraki satırı okuma
ligne = fic.readline().strip()
except IOError as erreur:
print(f"Erreur d'exploitation du fichier {FILE_NAME} : {erreur}")
sys.exit()
finally:
# dosya açıksa kapatılır
if fic:
fic.close()
# "dico" sözlüğünden yararlanma
affiche_infos(dico, "login10")
affiche_infos(dico, "X")
Notlar:
-
- satır: dosya yazma modunda açılır (w=write). Dosya zaten mevcutsa, üzerine yazılır;
- 30-34. satırlar: metin dosyasına 100 satır eklenir;
-
- satır: metin dosyasına bir satır yazmak için. [write] yöntemi satır sonu işaretini eklemez. Bu nedenle, yazılan metinde bu işaretin yer alması gerekir;
- satır 35-37: olası istisnaların yönetimi;
- satır 37: komut dosyasının yürütülmesinden vazgeçilir (ancak finally bloğu yürütüldükten sonra);
- satır 38-41: her durumda, hata olsun ya da olmasın, dosya açıksa kapatılır;
- satır 47: dosyanın okuma modunda açılması (r=read);
-
- satır: boş bir sözlük tanımlanır;
-
- satır: [readline] yöntemi, satır sonu işaretini de içerecek şekilde bir metin satırını okur. [strip] yöntemi, dizgenin başındaki ve sonundaki "boşlukları" kaldırır. "Boşluk" derken, beyaz karakter, satır sonu işareti, sayfa sonu, sekme ve diğer bazı karakterler kastedilmektedir. Dolayısıyla burada, [ligne], [\r\n] (Windows) veya [\n] (Unix) gibi satır sonu karakterlerini içermez;
-
- satır: Boş bir satır elde edilene kadar dosya işlenir;
- 54-64. satırlar: metin dosyası [dico] sözlüğüne aktarılır. Anahtar, [login] alanıdır; değer ise [uid:gid:infos:dir:shell] alanlarıdır;
- 65-67. satırlar: Olası istisnaların yönetimi;
- 68-71. satırlar: hata olsun ya da olmasın, her durumda dosyanın kapatılması;
- 74-75. satırlar: [dico] sözlüğünün kullanılması;
[data/infos.txt] dosyası:
Ekran çıktıları:
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fichiers/fic_01.py
login10 : ['uid10', 'gid10', 'infos10', 'dir10', 'shell10']
la clé [X] n'existe pas
Process finished with exit code 0
7.2. [fic_02] komut dosyası: UTF-8 ile kodlanmış metin dosyalarını yönetme
Belgenin devamında, yalnızca UTF-8 ile kodlanmış metin dosyalarını işleyeceğiz. Öncelikle PyCharm'i yapılandıracağız:

- [5-6] olarak: proje dosyaları için UTF-8 kodlamasını seçin;
UTF-8 kodlamalı bir dosya oluşturmak için şu adımları uygulayabilirsiniz (fic-02):
# ithalatlar
import codecs
# bir metin dosyasına utf8 olarak yazma
# istisnalar yönetilmez
file=codecs.open("./data/utf8.txt","w","utf8")
file.write("Hélène est partie à Bâle pendant l'été chez sa grand-mère")
file.close()
Notlar
-
- satır: Dosyaların kodlamasını yönetmek için [codecs] modülünü içe aktarırız;
-
- satır: [codecs.open] yöntemi, klasik [open] işlevi gibi kullanılır. Ancak istenen (oluşturma) veya mevcut (okuma) kodlamayı belirtebiliriz. Dosya açıldıktan sonra, 6. satırda elde edilen [file] nesnesi, klasik bir dosya gibi kullanılır;
-
- satır: aksanlı karakterler kullanılmıştır; bu karakterlerin çoğu zaman kullanılan karakter koduna göre farklı gösterimlere sahiptir;
Sonuçlar
Elde edilen [data/utf8.txt] dosyasını (bkz. 6. satır) açtığımızda, şu sonuç elde edilir:

7.3. [fic_03] komut dosyası: ISO-8859-1 ile kodlanmış metin dosyalarını yönetme
[fic_03] komut dosyası, [fic_02] komut dosyasıyla aynı işlevi görür, ancak metin dosyasını ISO-8859-1 formatında kodlar. Elde edilen dosyalar arasındaki farkı göstermek istiyoruz:
# ithalatlar
import codecs
# metin dosyasına iso-8859-1 ile yazma
# istisnalar işlenmiyor
file=codecs.open("./data/iso-8859-1.txt","w","iso-8859-1")
file.write("Hélène est partie à Bâle pendant l'été chez sa grand-mère")
file.close()
- satırda oluşturulan [data/iso-8859-1] dosyasını açtığımızda, şu sonucu elde ederiz:

Projeyi UTF-8 dosyalarıyla çalışacak şekilde yapılandırdığımız için, PyCharm, [iso-8859-1.txt] dosyasını UTF-8 olarak açmaya çalıştı. [1] dosyasının UTF-8 dosyası olmadığını algılayabiliyor. Ardından, dosyayı farklı bir kodlamada yeniden yüklemeyi öneriyor:

- [3-5]: dosya, ISO-8859-1 kodlaması kullanılarak yeniden yüklenir;

- [6]'e, aynı dosya ancak farklı bir kodlamayla görüntülenir;
Proje ayarlarına geri dönersek:

- [6-7] dosyasında, Pycharm'ın [iso-8859-1.txt] dosyasının ISO-8859-1 kodlamasıyla açılması gerektiğini kaydettiğini görüyoruz. Dolayısıyla bu, [5] kuralına bir istisnadır;
7.4. [json_01] komut dosyası: jSON dosyasının yönetimi
JSON, JavaScript Nesne Notasyonu anlamına gelir. Adından da anlaşılacağı gibi, bu, JavaScript dilindeki nesnelerin metin olarak temsil edilme biçimidir. Burada bunu Python nesneleriyle kullanacağız.
[data/in.json] ile yönetilen jSON dosyası şu şekilde olacaktır:

- [2] dosyasında, [in.json] dosyasının metin içeriğinin bir Python sözlüğünü temsil edebileceği görülüyor. PyCharm bu metni biçimlendirmiştir (Ctrl-Alt-L), ancak tek satırda olsaydı da bu durum hiçbir şeyi değiştirmezdi. Metnin biçimi, sözdizimsel olarak bir Python nesnesini temsil ettiği sürece hiçbir önemi yoktur;
[json-01] betiği, bu dosyadan nasıl yararlanılacağını gösterir:
# ithalatlar
import codecs
import json
import sys
# jSON dosyasının okunması / yazılması
inFile=None
outFile=None
try:
# jSON dosyasının okuma modunda açılması
inFile = codecs.open("./data/in.json", "r", "utf8")
# içeriği bir sözlüğe aktarma
data = json.load(inFile)
# okunan verilerin görüntülenmesi
print(f"data={data}, type(data)={type(data)}")
limites = data['limites']
print(f"limites={limites}, type(limites)={type(limites)}")
print(f"limites[1]={limites[1]}, type(limites[1])={type(limites[1])}")
# [data] sözlüğünün bir json dosyasına aktarılması
outFile = codecs.open("./data/out.json", "w", "utf8")
json.dump(data, outFile)
except BaseException as erreur:
# hata mesajı görüntülenir ve program sonlandırılır
print(f"L'erreur suivante s'est produite : {erreur}")
sys.exit()
finally:
# Açık olan dosyalar varsa kapatılır
if inFile:
inFile.close()
if outFile:
outFile.close()
Notlar
-
- satır: JSON dosyasını işlemek için [json] modülünü içe aktarıyoruz;
-
- satır: UTF-8 ile kodlanmış jSON dosyalarını işleyeceğiz. Burada [data/in.json] dosyasını [codecs] modülüyle açıyoruz;
-
- satır: [json.load] yöntemi, jSON dosyasının içeriğini okur ve [data] değişkenine atar. Bu değişkenin türü burada bir sözlük olacaktır;
- 15-18. satırlar: Bir Python sözlüğü elde ettiğimizi göstermek için, sözlüğün bazı öğelerini ekrana yazdırıyoruz;
- 20-21. satırlar: Ters işlemi gerçekleştiriyoruz: [data] sözlüğü, [json.dump] yöntemi kullanılarak UTF-8 adında bir dosyaya yazılır;
- 22-25. satırlar: Olası istisnaların yönetimi;
- 26-31. satırlar: Hata olsun ya da olmasın, her durumda açılmış olabilecek dosyalar kapatılır;
Sonuçlar
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fichiers/json_01.py
data={'limites': [9964, 27519, 73779, 156244, 0], 'coeffR': [0, 0.14, 0.3, 0.41, 0.45], 'coeffN': [0, 1394.96, 5798, 13913.69, 20163.45], 'PLAFOND_QF_DEMI_PART': 1551, 'PLAFOND_REVENUS_CELIBATAIRE_POUR_REDUCTION': 21037, 'PLAFOND_REVENUS_COUPLE_POUR_REDUCTION': 42074, 'VALEUR_REDUC_DEMI_PART': 3797, 'PLAFOND_DECOTE_CELIBATAIRE': 1196, 'PLAFOND_DECOTE_COUPLE': 1970, 'PLAFOND_IMPOT_COUPLE_POUR_DECOTE': 2627, 'PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE': 1595, 'ABATTEMENT_DIXPOURCENT_MAX': 12502, 'ABATTEMENT_DIXPOURCENT_MIN': 437}, type(data)=<class 'dict'>
limites=[9964, 27519, 73779, 156244, 0], type(limites)=<class 'list'>
limites[1]=27519, type(limites[1])=<class 'int'>
Process finished with exit code 0
- 2-4. satırlar, jSON dosyasında bulunan sözlüğün doğru bir şekilde alındığını göstermektedir;
Şimdi, [data/out.json] dosyasının içeriğine bakalım:

Dosyanın metni tek satırda yer alıyor. Ancak PyCharm, jSON dosyalarını tanıyor ve bu dosyaları, Python dosyaları ve diğerleri gibi Ctrl-Alt-L tuşlarıyla biçimlendirebiliyoruz. Böylece şu sonucu elde ediyoruz:

7.5. [json_02] komut dosyası: UTF-8 ile kodlanmış jSON dosyalarının yönetimi
UTF-8 ile kodlanmış bir jSON dosyası iki şekilde olabilir:
# ithalatlar
import codecs
import json
import sys
# sözlük
data = {'marié': 'oui', 'impôt': 1340}
# bir dosya yazma jSON
out_file1 = None
out_file2 = None
try:
# [data] sözlüğünün bir json dosyasına aktarılması
out_file1 = codecs.open("./data/out1.json", "w", "utf8")
json.dump(data, out_file1, ensure_ascii=True)
# [data] sözlüğünü bir json dosyasına aktarma
out_file2 = codecs.open("./data/out2.json", "w", "utf8")
json.dump(data, out_file2, ensure_ascii=False)
except BaseException as erreur:
# hata mesajı görüntülenir ve program sonlandırılır
print(f"L'erreur suivante s'est produite : {erreur}")
sys.exit()
finally:
# Açık olan dosyalar varsa kapatılır
if out_file1:
out_file1.close()
if out_file2:
out_file2.close()
…
- bu betikte, [data] sözlüğü (7. satır) iki jSON dosyasına (14. ve 17. satırlar) yazılır;
-
- ve 17. satırlar: Her iki durumda da UTF-8 adlı bir metin dosyası oluşturulur;
-
- satır: Sözlüğü yazarken, [ensure_ascii=True] adlı parametre kullanılır;
- satır 18: sözlük yazılırken, [ensure_ascii=False] adlı parametre kullanılır;
İşte elde edilen iki dosya:

- [out1.json] dosyasında, aksanlı karakterler, UTF-8 kodlarını temsil eden bir dizi karakterle değiştirilmiştir. Buna bazen “kaçış karakteri” denir. Teknik olarak, [out1.json] ikili dosyasında, [marié] dosyasındaki “é” karakteri için, UTF-8 kodlu 6 karakterin [\u00e9] ikili kodları sırayla yer almaktadır;
- [out2.json] dosyasında ise aksanlı karakterler olduğu gibi bırakılmıştır. Bu, [out2.json] ikili dosyasında bu karakterlerin UTF-8 ikili kodlarıyla temsil edildiği anlamına gelir ile temsil edilir (yani out1 için 6 yerine tek bir UTF-8 kodu). [marié] dosyasındaki é karakteri için ise 4 baytlık [00e9] ikili kodu bulunur;
- kullanılacak biçimi belirleyen, [ensure_ascii] yönteminin [json.dump] parametresinin değeridir;
Bazı uygulamalar, jSON dosyaları için 'escape' edilmiş UTF-8 kullanır. Bu durumda [ensure_ascii=True] değeri kullanılmalıdır. Bu değer aslında varsayılan değerdir. Dolayısıyla, [ensure_ascii] parametresi kullanılmazsa, 'escape' edilmiş jSON ve UTF-8 dosyalarıyla çalışılacaktır.
Komut dosyası şu şekilde devam eder:
# ithalatlar
import codecs
import json
import sys
# sözlük
data = {'marié': 'oui', 'impôt': 1340}
…
# jSON dosyalarının yeniden okunması
in_file1 = None
in_file2 = None
try:
# jSON 1 dosyasının bir sözlüğe aktarılması
in_file1 = codecs.open("./data/out1.json", "r", "utf8")
dico1 = json.load(in_file1)
# görüntüleme
print(f"dico1={dico1}")
# jSON 2 dosyasının bir sözlüğe aktarılması
in_file2 = codecs.open("./data/out2.json", "r", "utf8")
dico2 = json.load(in_file2)
# görüntüleme
print(f"dico2={dico2}")
except BaseException as erreur:
# hata mesajı görüntülenir ve program sonlandırılır
print(f"L'erreur suivante s'est produite : {erreur}")
sys.exit()
finally:
# açık olan dosyalar varsa kapatma
if in_file1:
in_file1.close()
if in_file2:
in_file2.close()
Notlar
- 11-34. satırlar: [out1.json, out2.json] dosyalarının her ikisinin de okunması ve her birinde okunan sözlüğün görüntülenmesi;
Sonuçlar
Şaşırtıcı bir şekilde, [json.load] işlevine (17. ve 22. satırlar) okunacak jSON dizesinin kodlama türünü (kaçış karakterli mi değil mi) belirtmeye gerek olmadığı görülmektedir. Her iki durumda da doğru sözlük elde ediliyor.