Skip to content

7. Metin dosyaları

Image

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:

    1. 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;
    1. 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);
    1. satır: boş bir sözlük tanımlanır;
    1. 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;
    1. 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ı:

1
2
3
4
5
6
login0:pwd0:uid0:gid0:infos0:dir0:shell0
login1:pwd1:uid1:gid1:infos1:dir1:shell1
login2:pwd2:uid2:gid2:infos2:dir2:shell2
login98:pwd98:uid98:gid98:infos98:dir98:shell98
login99:pwd99:uid99:gid99:infos99:dir99:shell99

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:

Image

  • [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

    1. satır: Dosyaların kodlamasını yönetmek için [codecs] modülünü içe aktarırız;
    1. 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;
    1. 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:

Image

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()
  1. satırda oluşturulan [data/iso-8859-1] dosyasını açtığımızda, şu sonucu elde ederiz:

Image

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:

Image

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

Image

  • [6]'e, aynı dosya ancak farklı bir kodlamayla görüntülenir;

Proje ayarlarına geri dönersek:

Image

  • [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:

Image

  • [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

    1. satır: JSON dosyasını işlemek için [json] modülünü içe aktarıyoruz;
    1. satır: UTF-8 ile kodlanmış jSON dosyalarını işleyeceğiz. Burada [data/in.json] dosyasını [codecs] modülüyle açıyoruz;
    1. 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:

Image

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:

Image

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;
    1. ve 17. satırlar: Her iki durumda da UTF-8 adlı bir metin dosyası oluşturulur;
    1. 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:

Image

  • [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

1
2
3
4
5
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_02.py
dico1={'marié': 'oui', 'impôt': 1340}
dico2={'marié': 'oui', 'impôt': 1340}

Process finished with exit code 0

Ş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.