Materjalid koostas ja kursuse viib läbi
Tartu Ülikooli arvutiteaduse instituudi programmeerimise õpetamise töörühm
< eelmine | 7. nädala sisukord | järgmine > |
7.3 Faili kirjutamine
Eespool oleme tutvunud mitmete võimalustega, kuidas failist andmeid lugeda. Failid ise on meil varem olemas olnud või oleme need teinud tekstiredaktoriga (ka Thonnyga kui tekstiredaktoriga). Nüüd vaatame, kuidas isetehtud programmiga andmeid faili kirjutada. Selleks pakub võimalusi funktsioon write (ingl kirjuta).
Järgmine programm kirjutab kasutajalt küsitud andmed faili.
nimi = input("Palun sisesta oma nimi: ") vanus = input("vanus: ") aadress = input("aadress: ") f = open("andmed3.txt", "w") f.write(nimi + "\n") f.write(vanus + "\n") f.write(aadress + "\n") f.close()
Faili kirjutamiseks tuleb funktsioonile open anda ka teine argument väärtusega "w" (nagu write). Kui sellise nimega fail juba eksisteerib, siis open(..., "w") teeb selle tühjaks. Erinevalt funktsioonist print ei tekita funktsioon write automaatselt reavahetusi. Selleks, et saada eri andmeid eri ridadele, lisasime reavahetuse sümboli käsitsi.
Proovime kirjutada programmi, mis küsib kasutajalt kaks failinime. Esimene fail peaks olema juba olemas ja seal peaks olema mingi tekst. Teine fail võiks olla uus. Programmi ülesanne on võtta esimese faili sisu, teisendada see suurtähtedesse ning kirjutada teise faili.
doonorNimi = input("Mis failist info võtta? ") aktseptorNimi = input("Millisesse faili info pannakse? ") doonorFail = open(doonorNimi, encoding="UTF-8") aktseptorFail = open(aktseptorNimi, "w") for rida in doonorFail: aktseptorFail.write(rida.upper()) doonorFail.close() aktseptorFail.close()
Programm töötab nii, et ekraanile ei väljastata midagi. Ometi on tegemist võimsa vahendiga - me saame failides olevad andmed teatud muudatustega teise faili kanda. Tähtede suureks muutmine ei ole muidugi midagi eriti võimsat, aga põhimõtteliselt saab nii palju keerulisemaid ja ka vajalikumaid asju teha. Võib-olla mingeid andmeid üldse mitte teise faili lubada!?
Ka faili kirjutamiseks saab määrata kodeeringu, näiteks open(aktseptorNimi, "w", encoding="UTF-8")
.
FAILI JUURDE. TEMPERATUURID VEEBIST FAILI
Eelmistes näidetes avasime selle faili, kuhu kirjutada tahtsime nii, et funktsiooni open teine argument oli "w". Kui fail oli juba olemas, siis tehti see fail enne kirjutamist tühjaks. Kui teine argument on "a", siis kirjutatakse olemasoleva faili lõppu. Kui sellist faili pole, siis see luuakse. Argument "a" tuleb ingliskeelsest sõnast append (lisa).
Järgmises programmis ongi faili avamisel teine argument "a"- kui fail on enne olemas, siis lisatakse ridu selle lõppu. Samuti saab ka siin määrata kodeeringu, näiteks open(failiNimi, "a", encoding="UTF-8")
.
Programmi loeb aadressilt http://meteo.physic.ut.ee/ aasta 2023 jaoks iga päeva keskmise temperatuuri ja kirjutab selle faili. Programm töötab umbes pool minutit. Kui võtta vähem kui terve aasta andmed, siis töötaks kiiremini. Programmis kasutatakse kahekordset tsüklit, mille põhjalikum käsitlus jääb sellest kursusest välja.
from urllib.request import urlopen fail = open("andmed.txt", "a") # fail avatakse juurde kirjutamiseks päevad = [31,28,31,30,31,30,31,31,30,31,30,31] aasta = 2023 for kuu in range(1,13): # välimine tsükkel kuude järjenumbrite kaupa for päev in range(1, päevad[kuu-1]+1): # sisemine tsükkel päevade kaupa # konkreetse päeva andmed vastus = urlopen("http://meteo.physic.ut.ee/et/showperiod.php?type=setday&year="+str(aasta)+"&month="+str(kuu)+"&day="+str(päev)) baidid = vastus.read() tekst = baidid.decode() otsitav = "<SMALL>keskmine</SMALL><BR><B>" algus = tekst.index(otsitav) # leitakse õige koht temp_algus = algus + len(otsitav) # siit algab temperatuur deg = tekst.index(" °") # siin lõpeb temp = tekst[temp_algus:deg] # viilutades leitakse temperatuur # funktsioon rjust paneb ühekohalisele päeva ja kuu järjenumbrile 0 ette, et oleks kahekohaline. fail.write(str(päev).rjust(2,"0")+"."+str(kuu).rjust(2,"0")+"."+str(aasta)+": "+str(temp)+"\n") vastus.close() fail.close()
Ülesanne
Tegeleme nüüd natuke salakirjadega. Nimelt ei kirjuta me faili mitte sümboli enda, vaid hoopis teise sümboli. Näiteks A asemel kirjutame tähestikus 4 kohta tagapool oleva tähe E. Näiteks on AEG on siis hoopis EIK. Tegemist on nihkešifriga, mis on ajalooliselt tuntud šifreerimisviis. Kui nihe on teada, siis on teksti lihtne käsitsigi dešifreerida, rääkimata arvutiga. Isegi siis, kui nihe pole teada, saab dešifreerimisega suhteliselt hõlpsasti hakkama.
Ühe tähe teiseks nihutamisel oleks mõistlik tähed nummerdada ja siis vastavalt nihke järjekorranumbrile juurde liita või sellest (dešifreerimise korral) lahutada. Väga loomulik oleks näiteks A järjekorranumbriks võtta 1, B korral 2 jne. Seda me siiski ei tee, sest tähtedel ja tegelikult paljudel teistelgi (sealhulgas nähtamatutel) märkidel on sellised järjekorranumbrid juba olemas. Vastava järjekorranumbri saame teada funktsiooniga ord. Katsetage järgmist programmi.
print(ord("A")) print(ord("a")) print(ord("ä")) print(ord("õ")) print(ord(" "))
Näeme, et täpitähed on meie loomulikust tähestikust hoopis eemal.
Vastupidi jälle funktsiooniga chr saame teada arvule vastava märgi.
print(chr(65))
Proovige ka päris suurte arvudega. Räägime neist pikemalt selle nädala silmaringimaterjalis.
Nüüd aga siis programm, mis kirjutab teksti šifreeritult faili.
def kodeeri(sümbol, nihe): return chr(ord(sümbol) + nihe) def šifreeri(failinimi, nihe): f = open(failinimi, "w") kiri = input("Sisesta lause ") for sümbol in kiri: f.write(kodeeri(sümbol, nihe)) f.close() failinimi = input("Faili nimi? ") nihe = int(input("Nihe? ")) šifreeri(failinimi, nihe)
Katsetage šifreerimise programmi.
Nüüd on aga küsimus, kuidas salakiri dešifreerida. Toome siin mõned ideed, mis võivad selles aidata.
- Funktsioon dekodeeri on funktsioonile kodeeri üsna sarnane. Kui šifreerimisel tuli nihe liita, siis dešifreerimisel tuleb see lahutada.
- Kui šifreerimisel avati fail kirjutamiseks, siis dešifreerimisel tuleb see avada lugemiseks.
- Sümbolite ühekaupa käsitlemiseks saab kasutada sellist tsüklit
while True: sümbol = f.read(1) # loetakse üks sümbol if sümbol == "": # kui enam pole break # tsükkel katkestatakse print(dekodeeri(?????????), end = "") # reavahetust ei tule
Küsimärgid tuleb asendada vastavalt sellele, kuidas funktsioon dekodeeri tehtud on.
< eelmine | 7. nädala sisukord | järgmine > |