1. fejezet
Miért kell fájl?
A változók tartalma a program futása végén elvész. Ha az adatoknak meg kell maradniuk – egy pontszámtábla, a beállítások, egy napló –, vagy ha a programnak mások által előállított adatokat kell feldolgoznia (egy osztálynévsort, mérési eredményeket), fájlba írunk, illetve fájlból olvasunk.
A szöveges fájl (.txt, .csv, .json, .py) karakterekből álló sorokat tartalmaz; ezt egy egyszerű szövegszerkesztő is megnyitja. A bináris fájl (kép, hang, PDF) tetszőleges bájtokból áll, és csak az adott formátumot ismerő program érti. A szöveges fájlnál a karakterkódolás mondja meg, melyik bájtsorozat melyik betűt jelenti: a mai szabvány az UTF-8, ezzel az ékezetes betűk is biztosan jól jelennek meg.
Hogyan működik itt? A böngészőben futó Python egy saját, a memóriában lévő munkakönyvtárral dolgozik. A példák alatt a „Munkakönyvtár” sáv mutatja a fájlokat: kattints egy fájl nevére, és megnézheted a tartalmát. Amit a program létrehoz vagy módosít, az zölden jelenik meg, és a következő futtatáskor is ott lesz – a ↺ gomb állítja vissza a kiinduló állapotot. A saját gépeden ugyanez a kód a valódi fájlrendszerben dolgozik: a relatív fájlnevet (adat.txt) az aktuális munkakönyvtárhoz képest keresi, vagyis ahhoz a mappához, ahonnan a programot elindítottad (VS Code-ban a megnyitott mappa). Tedd az adatfájlt a .py mellé, és nyisd meg a mappát VS Code-ban (Fájl → Mappa megnyitása…). Ha mégis FileNotFoundError jön, írasd ki, hol keresi a fájlt: import os, majd print(os.getcwd()).
2. fejezet
Megnyitás és bezárás: open() és with
A fájllal való munka három lépés: megnyitás, olvasás vagy írás, bezárás. Az open() függvény egy fájlobjektumot ad vissza, amelyen keresztül olvasunk és írunk.
with open("fajlnev.txt", "r", encoding="utf-8") as f:
tartalom = f.read()
# itt a fájl már be van zárva
"fajlnev.txt"a fájl neve (a munkakönyvtárhoz képest)"r"a megnyitás módja (lásd a táblázatot)encoding="utf-8"a karakterkódolás – mindig add meg.as fa fájlobjektum neve a blokkban
| Mód | Jelentés | Ha a fájl nem létezik | Ha létezik |
|---|---|---|---|
"r" | olvasás (ez az alapértelmezett) | FileNotFoundError | az elejéről olvas |
"w" | írás | létrehozza | kiüríti, majd az elejére ír |
"a" | hozzáfűzés (append) | létrehozza | a végére ír, a régi tartalom megmarad |
"x" | kizárólagos létrehozás | létrehozza | FileExistsError |
"rb", "wb" | bináris olvasás / írás | mint fent, de bájtokkal (nincs encoding) | |
A with blokk végén a Python automatikusan bezárja a fájlt – akkor is, ha a blokkban hiba történt. Bezárás nélkül a kiírt adat egy része a memóriában ragadhat, és (főleg Windowson) más program nem tudja törölni vagy átnevezni a fájlt. A régebbi, with nélküli forma (f = open(…) … f.close()) is működik, de ott a bezárásról neked kell gondoskodnod.
3. fejezet
Olvasás
| Módszer | Eredmény |
|---|---|
f.read() | a teljes (hátralévő) tartalom egyetlen szövegként |
f.readline() | a következő sor (a végén a \n-nel); a fájl végén üres szöveg |
f.readlines() | az összes sor egy listában (mindegyik végén \n) |
for sor in f: | soronkénti bejárás – a leggyakoribb és nagy fájlnál is takarékos |
with open("nevsor.txt", encoding="utf-8") as f:
egesz = f.read()
print(repr(egesz))
with open("nevsor.txt", encoding="utf-8") as f:
for sor in f:
print("Szia,", sor.strip() + "!")
A repr() megmutatja a láthatatlan karaktereket is: minden sor végén ott a \n sorvége-jel. Ezért a beolvasott sorokat általában a strip() metódussal tisztítjuk meg – különben a print saját sortörésével együtt üres sorok keletkeznének.
Mit ír ki?
sor = "alma\n" print(len(sor), len(sor.strip()))
4 45 46 4
A \n egyetlen karakter (a sorvége-jel), így a szöveg 5 hosszú. A strip() levágja a szöveg elején és végén álló szóközöket, tabulátorokat és sortöréseket.
4. fejezet
Írás és hozzáfűzés
Íráshoz "w" vagy "a" módban nyitjuk meg a fájlt. A f.write(szoveg) pontosan azt írja ki, amit kap – sortörést nem tesz a végére, azt nekünk kell ("\n"). Kényelmesebb lehet a print(…, file=f), amely ugyanúgy működik, mint a képernyőre írás, csak a fájlba ír.
gyumolcsok = ["alma", "körte", "szilva"]
with open("lista.txt", "w", encoding="utf-8") as f:
f.write("Bevásárlólista\n")
for i, gy in enumerate(gyumolcsok, start=1):
print(f"{i}. {gy}", file=f)
with open("lista.txt", encoding="utf-8") as f:
print(f.read())
Futtasd, majd kattints a Munkakönyvtárban a lista.txt-re. Futtasd újra: a tartalom ugyanaz marad, mert a "w" mód minden megnyitáskor kiüríti a fájlt.
Hozzáfűzés
A "a" mód a meglévő tartalom végére ír. Tipikus használat a napló (log): minden futás egy új sort tesz a végére. Futtasd többször egymás után, és nézd meg a naplo.txt-t.
import random
eredmeny = random.randint(1, 6)
with open("naplo.txt", "a", encoding="utf-8") as f:
f.write(f"dobás: {eredmeny}\n")
with open("naplo.txt", encoding="utf-8") as f:
sorok = f.readlines()
print(f"Eddig {len(sorok)} dobás van a naplóban. Az utolsó: {sorok[-1].strip()}")
A „w” mód nem kérdez. Ha egy létező fájlt "w" módban nyitsz meg, a tartalma azonnal elvész – még akkor is, ha végül semmit sem írsz bele. Ha egy fájlt bővíteni akarsz, "a" kell; ha módosítani, akkor előbb olvasd be, módosítsd a memóriában, és utána írd vissza.
Mit ír ki?
for i in range(3):
with open("proba.txt", "w", encoding="utf-8") as f:
f.write(f"{i}. sor\n")
with open("proba.txt", encoding="utf-8") as f:
print(len(f.readlines()))
130
A "w" mód minden megnyitáskor kiüríti a fájlt, így a három kör közül csak az utolsó írása marad meg: egyetlen sor (2. sor). "a" módban három sor lenne a fájlban.
5. fejezet
Táblázatos adatok: CSV
A CSV (comma-separated values) egyszerű táblázatformátum: minden sor egy rekord, a mezőket egy elválasztójel tagolja. A magyar Excel pontosvesszőt használ (mert a vessző nálunk tizedesjel), ezért gyakran ; az elválasztó. Az első sor sokszor a fejléc (az oszlopok neve).
Kézzel: split()
osszeg = 0
db = 0
with open("diakok.csv", encoding="utf-8") as f:
fejlec = f.readline()
for sor in f:
nev, osztaly, pont = sor.strip().split(";")
osszeg += int(pont)
db += 1
if int(pont) >= 80:
print(f"{nev} ({osztaly}): {pont} pont – kiváló")
print(f"Átlag: {osszeg / db:.1f} pont")
A fejlécet egy readline() „elnyeli”, így a ciklus már csak az adatsorokat kapja. A split(";") a sort mezőkre bontja, a kicsomagolás pedig rögtön nevet ad nekik. Ne feledd: a fájlból beolvasott szám is szöveg, számoláshoz int() kell.
A csv modullal
A csv modul kezeli a bonyolultabb eseteket is (pl. idézőjelek közé tett mezőt, amelyben elválasztójel van). A DictReader minden sort szótárként ad vissza, a fejléc neveivel kulcsként; a writer pedig listákból készít sorokat.
import csv
with open("diakok.csv", encoding="utf-8", newline="") as f:
olvaso = csv.DictReader(f, delimiter=";")
diakok = list(olvaso)
print(diakok[0])
with open("kivalok.csv", "w", encoding="utf-8", newline="") as f:
iro = csv.writer(f, delimiter=";")
iro.writerow(["nev", "pont"])
for d in diakok:
if int(d["pont"]) >= 80:
iro.writerow([d["nev"], d["pont"]])
print("Elkészült a kivalok.csv.")
A newline="" a csv modul ajánlása: így a modul maga kezeli a sorvégeket, és Windows alatt sem keletkeznek üres sorok.
6. fejezet
Szerkezetes adatok: JSON
A JSON szöveges formátum, amely a Python szótáraihoz és listáihoz nagyon hasonló szerkezetet ír le – ezért kiválóan alkalmas arra, hogy egy program teljes adatállapotát (beállítások, pontszámok, egy játékos mentése) elmentsük és visszatöltsük. A webes szolgáltatások is jellemzően JSON-ban adnak adatot.
import json
with open("pontok.json", encoding="utf-8") as f:
pontok = json.load(f)
print("Betöltve:", pontok)
pontok["Dóra"] = 1450
legjobb = max(pontok, key=pontok.get)
print("A legjobb:", legjobb, pontok[legjobb])
with open("pontok.json", "w", encoding="utf-8") as f:
json.dump(pontok, f, ensure_ascii=False, indent=2)
print("Elmentve.")
json.load(f)beolvassa a fájlt, és Python-szótárat/listát ad vissza;json.dump(adat, f)kiírja.- Az
ensure_ascii=Falsemiatt az ékezetes betűk olvashatók maradnak a fájlban, azindent=2pedig tagolja a kimenetet. - A
max(pontok, key=pontok.get)azt a kulcsot adja, amelyhez a legnagyobb érték tartozik.
A JSON-ban a szövegek mindig kettős idézőjelesek, a logikai értékek true/false, az „üres” érték null (Pythonban True, False, None). A tuple-ből JSON-tömb lesz (visszaolvasva tehát lista), a halmazt viszont a json nem tudja kiírni (TypeError) – előbb listává kell alakítani. Fontos az is, hogy a JSON-ban a szótár kulcsa mindig szöveg: a {1: "a"} kiírva {"1": "a"}, visszatöltve tehát "1" kulcs lesz.
7. fejezet
Ha valami nem sikerül: hibakezelés
Fájlkezelésnél sok minden elromolhat, ami nem a program hibája: a fájl nem létezik, nincs jogosultság hozzá, hibás benne egy adat. Ilyenkor a program kivételt (exception) kap. A try–except szerkezettel a kivételt el tudjuk kapni, és értelmes üzenetet adhatunk összeomlás helyett.
fajlnev = input("Melyik fájlt nyissam meg? ")
try:
with open(fajlnev, encoding="utf-8") as f:
sorok = f.readlines()
except FileNotFoundError:
print(f"Nincs ilyen fájl: {fajlnev}")
else:
osszeg = 0
hibas = 0
for sor in sorok:
try:
osszeg += int(sor)
except ValueError:
hibas += 1
print(f"Összeg: {osszeg}, hibás sor: {hibas}")
Futtasd kétszer: egyszer a nincs.txt, egyszer a szamok.txt névvel. A try blokk figyelt módon fut; ha benne a megnevezett hiba történik, a megfelelő except ág veszi át a vezérlést. Az else ág akkor fut, ha nem volt hiba.
| Hiba | Mikor fordul elő? |
|---|---|
FileNotFoundError | nincs ilyen fájl (elírt név, rossz mappa, hiányzó kiterjesztés) |
PermissionError | nincs jogosultság (pl. írásvédett vagy más program által zárolt fájl) |
UnicodeDecodeError | a fájl nem a megadott kódolású (pl. régi, nem UTF-8 fájl) |
ValueError | a beolvasott szöveg nem alakítható számmá |
json.JSONDecodeError | hibás JSON-tartalom |
Mindig konkrét hibát kapj el (except FileNotFoundError:), ne az összeset (except:). A mindent elkapó ág a programozási hibákat (elírt változónév, rossz index) is elrejti, és nagyon nehéz lesz megtalálni őket.
8. fejezet
Kitekintés: bináris fájlok
Bináris módban ("rb", "wb") nincs karakterkódolás: a fájl nyers bájtjait kapjuk meg egy bytes értékként. A képek, hangok formátumát a fájl elején álló „varázsszám” (fejléc) azonosítja – a PNG-képek például mindig ugyanazzal a 8 bájttal kezdődnek:
with open("kep.png", "rb") as f:
adat = f.read()
print("Méret:", len(adat), "bájt")
print("Az első 8 bájt:", adat[:8])
print("PNG-kép?", adat[:8] == b"\x89PNG\r\n\x1a\n")
szelesseg = int.from_bytes(adat[16:20], "big")
magassag = int.from_bytes(adat[20:24], "big")
print(f"Képméret: {szelesseg} × {magassag} képpont")
A bájtok értelmezéséhez ismerni kell a formátum leírását – a PNG-nél a szélesség és a magasság a 16-os indextől (a 17. bájttól) kezdve, 4-4 bájton áll. A gyakorlatban képekhez kész könyvtárat (pl. Pillow) használunk; ez már túlmutat ezen a tananyagon.
9. fejezet
Gyakorló feladatok
A feladatok a munkakönyvtár fájljaival dolgoznak (a kódpanel alatt megnézheted őket). Ahol a programnak fájlt kell írnia, a gép a létrejött fájl tartalmát is összeveti az elvárttal.
Sorok számozása
Olvasd be a vers.txt fájlt (egy rövid, négysoros szöveg, a versszakok között üres sorral), és írd ki a sorait sorszámmal ellátva. Az üres sorokat ne számozd, hanem hagyd ki.
1. Reggel köd ült a völgyön, 2. délre kisütött a nap. 3. Este a szél feltámadt, 4. és a fák közt suttogott.
szam = 0
with open("vers.txt", encoding="utf-8") as f:
for sor in f:
sor = sor.strip()
if sor != "":
szam += 1
print(f"{szam}. {sor}")
Tipp
for sor in f:, a strip()-elt sorral dolgozz. A számláló csak a nem üres soroknál nő.
Mérések átlaga
A meresek.txt soronként egy valós számot (hőmérsékletet) tartalmaz. Írd ki a mérések számát, a legkisebbet, a legnagyobbat és az átlagot egy tizedesjegyre.
Mérések: 6 Legkisebb: -2.5 Legnagyobb: 11.0 Átlag: 4.2
ertekek = []
with open("meresek.txt", encoding="utf-8") as f:
for sor in f:
ertekek.append(float(sor))
print("Mérések:", len(ertekek))
print("Legkisebb:", min(ertekek))
print("Legnagyobb:", max(ertekek))
print(f"Átlag: {sum(ertekek) / len(ertekek):.1f}")
Tipp
Gyűjtsd a float(sor) értékeket egy listába (a float() a sorvégi \n-t elviseli), utána jöhet a min, max, sum, len.
Bevásárlólista mentése
Olvass be tételeket üres sorig, és írd őket a lista.txt fájlba, soronként egyet, sorszámmal. A végén írd ki a képernyőre: 3 tétel mentve.
Tétel: kenyér Tétel: tej Tétel: alma Tétel: 3 tétel mentve. lista.txt: 1. kenyér 2. tej 3. alma
tetelek = []
tetel = input("Tétel: ")
while tetel != "":
tetelek.append(tetel)
tetel = input("Tétel: ")
with open("lista.txt", "w", encoding="utf-8") as f:
for i, t in enumerate(tetelek, start=1):
f.write(f"{i}. {t}\n")
print(f"{len(tetelek)} tétel mentve.")
Tipp
Előbb gyűjtsd a tételeket listába, utána egyszer nyisd meg a fájlt "w" módban. A write() nem tesz sortörést – írd hozzá a "\n"-t (vagy használd: print(…, file=f)).
Átlag fölött
Az eredmenyek.csv fejléces, pontosvesszővel tagolt fájl (nev;pont). Írd ki az átlagpontszámot egy tizedesre, majd azok nevét (a fájl sorrendjében), akik az átlag fölött teljesítettek.
Átlag: 68.5 Átlag fölött: Kiss Anna Tóth Csilla Szabó Dénes
nevek = []
pontok = []
with open("eredmenyek.csv", encoding="utf-8") as f:
f.readline()
for sor in f:
nev, pont = sor.strip().split(";")
nevek.append(nev)
pontok.append(int(pont))
atlag = sum(pontok) / len(pontok)
print(f"Átlag: {atlag:.1f}")
print("Átlag fölött:")
for i in range(len(nevek)):
if pontok[i] > atlag:
print(nevek[i])
Tipp
Két menet kell: előbb az átlag (ehhez minden pont kell), utána a válogatás. Ezért tárold a neveket és a pontokat egy-egy listában (vagy egy szótárban). A fejlécet egy readline() nyeli el.
Ranglista JSON-ban
A ranglista.json egy szótár: név → pontszám. Kérj be egy nevet és egy pontszámot. Ha a név új, vedd fel; ha már szerepel, csak akkor írd felül, ha az új pontszám nagyobb. Mentsd vissza a fájlt (ensure_ascii=False, indent=2), majd írd ki a ranglistát pontszám szerint csökkenő sorrendben, sorszámmal.
Név: Emese Pont: 1500 1. Emese – 1500 2. Csilla – 1325 3. Anna – 1200 4. Bence – 980
import json
with open("ranglista.json", encoding="utf-8") as f:
pontok = json.load(f)
nev = input("Név: ")
pont = int(input("Pont: "))
if nev not in pontok or pont > pontok[nev]:
pontok[nev] = pont
with open("ranglista.json", "w", encoding="utf-8") as f:
json.dump(pontok, f, ensure_ascii=False, indent=2)
helyezes = 1
for n in sorted(pontok, key=pontok.get, reverse=True):
print(f"{helyezes}. {n} – {pontok[n]}")
helyezes += 1
Tipp
A feltétel: if nev not in pontok or pont > pontok[nev]: – a rövidzár miatt a pontok[nev] csak létező névnél értékelődik ki. Csökkenő rendezés érték szerint: sorted(pontok, key=pontok.get, reverse=True).
Biztonságos összegzés
Kérj be egy fájlnevet. Ha a fájl nem létezik, írd ki: Nincs ilyen fájl: …. Ha létezik, adja össze a soraiban álló egész számokat; a számmá nem alakítható sorokat hagyd ki, és számold meg őket. A végén: Összeg: 49, kihagyott sor: 1.
nev = input("Fájlnév: ")
try:
with open(nev, encoding="utf-8") as f:
sorok = f.readlines()
except FileNotFoundError:
print("Nincs ilyen fájl:", nev)
else:
osszeg = 0
kihagyott = 0
for sor in sorok:
try:
osszeg += int(sor)
except ValueError:
kihagyott += 1
print(f"Összeg: {osszeg}, kihagyott sor: {kihagyott}")
Tipp
Két külön try kell: egy a megnyitás köré (FileNotFoundError), egy az int()-es átalakítás köré a cikluson belül (ValueError).
10. fejezet
Összefoglalás
| Eszköz | Lényeg |
|---|---|
with open(nev, mod, encoding="utf-8") as f: | megnyitás; a blokk végén automatikus bezárás |
"r", "w", "a" | olvasás; írás (kiürít!); hozzáfűzés |
for sor in f:, sor.strip() | soronkénti olvasás, a sorvége-jel levágása |
f.write(s), print(…, file=f) | írás; a write nem tesz sortörést |
split(";"), csv | táblázatos (CSV) adatok |
json.load, json.dump | szótárak és listák mentése, betöltése |
try / except / else | konkrét hibák (FileNotFoundError, ValueError) kezelése |
Gyakorold tovább: írj egy jegyzetfüzet-programot: induláskor töltse be a jegyzetek.json-t (ha nincs, üres listával induljon), egy menüből lehessen jegyzetet felvenni, listázni és törölni, kilépéskor pedig mentse vissza a fájlt.