Python: Файлдармен жұмыс
Бағдарлама жұмыс істеп тұрғанда сен енгізген сандарды, есептелген нәтижені компьютер есінде сақтайды. Бірақ бағдарламаны жауып тастасаң ше? Сол деректер қайда кетеді? Дәл осы сұраққа жауап беретін тақырыппен танысамыз — Python-да файлдармен жұмыс істеу. Бұл тақырып ҰБТ-да жиі кездеседі: файлдан сандарды оқу, оларды өңдеп, нәтижені басқа файлға жазу — типтік бағдарламалау есептерінің бірі.
Ойланып көр: телефоныңда «Ескертпелер» қолданбасына бірдеңе жазып, телефонды өшіріп тастасаң, келесі күні ашқанда сол жазба орнында тұра ма? Иә, тұрады. Ал енді бағдарламаны ойлап көрейік: егер сен Python бағдарламасында бір айнымалыға санды сақтасаң, бағдарламаны жауып тастасаң, сол сан қайда кетеді?
Мұнда қызық мәселе бар: компьютердің жедел жады (RAM) тек бағдарлама жұмыс істеп тұрған кезде ғана деректі есінде сақтайды. Бағдарлама жабылысымен немесе компьютер сөнсімен, RAM-дағы бәрі жойылады. Ал «Ескертпелер» қолданбасындағы жазба неге жоғалмайды? Себебі ол жазба RAM-да емес, қатқыл дискіде (HDD немесе SSD) сақталады.
Файл — деректерді тұрақты жадта (қатқыл диск) ұзақ уақыт сақтауға арналған, атауы берілген аймақ. Python-да екі түрі бар: мәтіндік файлдар (белгісіз ұзындықтағы жолдар) және екілік (бинарлық) файлдар (сурет, дыбыс, видео кодтары).
Анықтаманы бөлшектеп көрейік: «Тұрақты жад (қатқыл диск)» — RAM-нан айырмашылығы, қуат сөнсе де ақпарат жоғалмайды. SSD немесе HDD — нақ осындай тұрақты жад түрлері. «Атауы берілген аймақ» — әр файлдың міндетті түрде аты бар (мыс. notes.txt), компьютер дәл осы атау арқылы керекті файлды табады.
«Мәтіндік файлдар» — ішінде әріптер, сандар, белгілер жолдар түрінде жазылған файлдар. Оларды Блокнотпен ашсаң, мазмұнын оқи аласың. «Екілік (бинарлық) файлдар» — суреттер, дыбыс, видео сияқты файлдар. Оларды қарапайым мәтін ретінде ашсаң, мағынасыз белгілер тізбегін көресің, өйткені бұл деректер арнайы кодпен сақталған.
Мысалы: task.txt файлы — мәтіндік файл, ішінде сандар немесе сөздер жазылған болуы мүмкін. Ал photo.jpg файлы — екілік файл, ішінде суреттің пиксельдік коды сақталған.
Файлды дәптерге ұқсатуға болады. Дәптердің аты бар (мыс. «Информатика дәптері»), ол сөреде тұрақты тұрады, тіпті үйде ешкім болмаса да. Дәл осылай, файл да компьютердің дискісінде атауымен тұрақты сақталады.
Ойланып көр: кітапханада керекті кітапты оқу үшін не істейсің? Алдымен сөредегі кітапты аласың (ашасың), содан кейін оқисың (немесе бетіне жазба қалдырасың), ал соңында кітапты қайта орнына қоясың (жабасың).
Python-да файлмен жұмыс та дәл осы үш қадамнан тұрады. Бірақ бір сұрақ туады: егер кітапты «жаппай» кетіп қалсаң, соңғы жазған жазбаларың кітапта шынымен сақтала ма? Қызығы — жоқ. Программа файлға жазған деректі алдымен уақытша буферге (жадтың кішкене бөлігіне) жинайды, содан кейін ғана дискіге толық «құяды». Ал бұл «құю» іс-әрекеті көбіне файлды жапқан кезде орындалады.
open()close() — дискіге құядыФайлмен жұмыс үш кезеңнен тұрады: 1) файлды ашу (
open), 2) оқу немесе жазу, 3) файлды жабу (close). Жабу командасы жазылмаса, файлға жазылған деректер сақталмай қалуы мүмкін.
«Ашу (open)» — Python-ға қай файлмен жұмыс істейтінін және оны не үшін ашатынын (оқу үшін бе, жазу үшін бе) айтамыз. «Оқу немесе жазу» — нақты іс-әрекет: файлдан деректі алу немесе оған жаңа дерек қосу. «Жабу (close)» — жұмыс аяқталғанын білдіреміз, барлық буферде қалған дерек дискіге құйылады, файл басқа бағдарламаларға да қолжетімді болады.
Неге дәл осы тәртіппен? Себебі компьютер бір уақытта бір файлды бірнеше бағдарламаға толық бақылаусыз бере алмайды — біреу жазып жатқанда, екіншісі сол сәтте оқып кетсе, қате туындауы мүмкін. Сондықтан «ашу → жұмыс → жабу» тәртібі деректің бұзылмауын қамтамасыз етеді.
Кітапханадан кітап алу процесін есіңе түсір: кітапты сұрайсың (ашу), оқисың немесе беттерін белгілейсің (оқу/жазу), содан кейін кітапханашыға қайтарасың (жабу). Қайтармай кетсең, келесі адам сол кітапты ала алмайды — файлды жаппасаң да, дерек толық «дайын» болмай қалады.
close() жазуды ұмытып кетеді, әсіресе файлға жазу кезінде. Нәтижесінде файл бос болып қалады немесе жазылған дерек жартылай ғана көрінеді. Есте сақта: жазу аяқталған соң close() шақыру міндетті.close() кезеңін елемеу — файлға жазылған дерек толық сақталмауына әкелуі мүмкін.Кітапты алғанда, оны әртүрлі мақсатпен аласың — кейде тек оқу үшін, кейде беттеріне жазба қалдыру үшін, кейде жаңа бет қосу үшін. Python-да да файлды ашқанда, оны қандай мақсатпен ашатыныңды нақты көрсету керек.
Сұрақ: егер сен бұрыннан бар файлға жаңа дерек жазғың келсе, бірақ Python оны «жаңадан құрып, бұрынғысын өшіріп» жазып жіберсе ше? Бұл — үлкен қате болар еді. Дәл осы себептен open() функциясында «режим» (mode) деген параметр бар — ол Python-ға файлды нақты қалай ашу керектігін айтады.
| Режим | Қызметі |
|---|---|
'r' | Файлды оқу үшін ашады (әдепкі режим) |
'w' | Жаңа файл жасап жазады; егер файл бар болса, мазмұны өшіріледі |
'a' | Бар файлды ашып, соңына жаңа деректі қосады |
'b' | Файлды екілік (бинарлық) режимде ашады |
't' | Файлды мәтіндік режимде ашады (әдепкі) |
'+' | Файлды оқу және жазу үшін бірге ашады |
Кестені қарапайым сөзбен қайталайық: 'r' — тек оқисың, ештеңе өзгертпейсің. 'w' — жаңадан жазасың, ескісі өшеді. 'a' — қосасың, ескісі қалады. 'b' мен 't' — файлдың түрін (екілік пе, мәтіндік пе) көрсетеді. '+' — екеуін де (оқу және жазу) бір мезетте істеуге мүмкіндік береді.
Неге дәл осылай жасалған? Себебі әртүрлі тапсырмаларда әртүрлі қауіп бар. Мысалы, бар деректі жоғалтып алмау үшін 'a' режимі қажет, ал жаңа есеп нәтижесін таза парақтан бастау үшін 'w' қолданылады.
Бұл — дәптерге жазу тәсілдеріне ұқсас: 'r' — дәптерді тек оқу (қалам алмайсың); 'w' — дәптердің бетін толығымен сызып тастап, жаңадан бастап жазу; 'a' — дәптердің соңғы бос бетінен жалғастырып жазу.
'w' режимін 'a' режимімен шатастырады. Нәтижесінде бар файлдағы маңызды дерек байқаусызда толық өшіп кетеді. Есте сақта: 'w' — әрқашан файлды «таза парақтан» бастайды, ал 'a' — бар деректі сақтап, тек соңына қосады.'r' — оқу, 'w' — қайта жазу (ескісін өшіріп), 'a' — соңына қосу. Дұрыс режимді таңдамасаң, деректі жоғалтып алуың мүмкін.Енді файлды нақты қалай ашатынымызды көрейік. Python-да open() функциясына файлдың тек атын ғана емес, кейде оның дискідегі толық орналасқан жерін (жолын) де көрсету керек.
open() функциясының жалпы синтаксисі: open(файл атауы, режим). Бірінші параметр салыстырмалы жол (мыс. "in.txt") немесе абсолютті жол (мыс. r"C:\Users\Desktop\in.txt") болуы мүмкін. Файл табылмаса, FileNotFoundError қатесі шығады.
«Салыстырмалы жол» — файл бағдарлама орналасқан қалтаның ішінде (немесе сол қалтада) жатса, тек атын жазу жеткілікті, мыс. "in.txt". «Абсолютті жол» — файл басқа қалтада, дискінің басқа жерінде жатса, оның толық мекенжайын жазу керек, мыс. r"C:\Users\Desktop\in.txt". «FileNotFoundError» — егер Python көрсетілген атпен немесе жолмен файлды таппаса, шығатын қате.
Неге кейде толық жол керек? Себебі компьютерде мыңдаған бірдей атты файлдар әртүрлі қалталарда жатуы мүмкін. Толық жол — нақты қай файлды айтып тұрғаныңды дәлме-дәл көрсетеді.
Мысалы: open("Input.txt", "r") — бағдарлама орналасқан қалтадан Input.txt файлын оқу үшін ашады. Ал open(r"C:\Users\Aigerim\Desktop\Input.txt", "r") — дискінің нақты көрсетілген жерінен файлды ашады.
Бұл — досыңа үйге қалай жету керектігін айтуға ұқсас. Егер дос сенімен бір ауладан тұрса, «менің үйім» деу жеткілікті (салыстырмалы жол). Ал дос басқа қаладан болса, толық мекенжайды (көше, үй нөмірі) айту керек (абсолютті жол).
\n — жаңа жол). Сондықтан Windows жолын дұрыс жазу үшін алдына r әрпін қою керек (мыс. r"C:\Users\..."), әйтпесе жол қате оқылуы мүмкін.open() функциясы файл атауы мен режимді қабылдайды. Файл сол қалтада жатса — қысқа ат жеткілікті, басқа жерде жатса — толық жол керек. Файл табылмаса, FileNotFoundError шығады.Файлды оқуға аштық делік. Енді сұрақ туады: файлдың бүкіл мазмұнын бірден аламыз ба, әлде жол-жолымен оқимыз ба? Бұл — кітапты бір отырыста түгел оқимыз ба, әлде бет ашып отырып оқимыз ба деген сұраққа ұқсас. Python бұл үшін бірнеше тәсіл ұсынады, әрқайсысы әртүрлі жағдайда ыңғайлы.
Оқу әдістері:
read() — файлдың барлық мазмұнын оқиды; readline() — бір жолды оқиды; read().split() — мазмұнды бос орын бойынша бөліктерге бөліп, тізім қайтарады (көбінесе map() функциясымен бірге сандарды бір жолдан оқу үшін қолданылады).
«read()» — файлдың түгел мазмұнын бір үлкен мәтін (жол) ретінде қайтарады. «readline()» — тек бір ғана жолды оқиды, келесі шақыруда келесі жолды оқиды. «read().split()» — алдымен бүкіл мазмұнды оқиды, содан кейін оны бос орын бойынша бөлек сөздерге/сандарға бөледі де, тізім (list) ретінде қайтарады.
Неге split() қажет? Себебі read() қайтаратын нәрсе — бір тұтас жол (string). Ал файлда «12 15» деп жазылған екі санды бөлек-бөлек алу үшін, оларды бір-бірінен ажырату керек. split() дәл осыны істейді — бос орын кездескен жерден бөліп тастайды.
Мысалы: файлда «12 15» деп жазылса, read() нәтижесі — "12 15" деген бір жол. Ал read().split() нәтижесі — ["12", "15"] деген тізім, яғни екі бөлек элемент.
map() функциясы әдетте осы жерде қолданылады: split() элементтерінің бәрі жол (string) түрінде болады, ал есептеу үшін оларды санға айналдыру керек. map(int, p) — тізімдегі әр элементті int() арқылы санға айналдырады.
read() — кітапты бір демде, түгел оқып шығу сияқты. readline() — кітапты бір-бір бет ашып оқу сияқты. split() — бір ұзын сөйлемді жеке сөздерге бөліп алу сияқты, мысалы «Мен мектепке барамын» деген сөйлемді жеке сөздерге бөлгенде.
split() арқылы алынған сандарды бірден қосу немесе көбейту әрекетіне қосады, бірақ ол элементтер әлі де жол (string) түрінде қалады. "12" + "15" — Python-да бұл "1215" деген жолды құрайды (сандарды қосу емес!). Сандарды нақты қосу үшін алдымен int() немесе map(int, ...) арқылы санға айналдыру керек.read() — бүкіл файлды бір жол ретінде оқиды, readline() — бір ғана жолды оқиды, read().split() — мазмұнды бөлек элементтерге бөліп тізім қайтарады. Сандармен жұмыс істеу үшін оларды міндетті түрде int() немесе float() арқылы санға айналдыру керек.Енді керісінше жағдайды қарастырайық: есепті шығардық, нәтиже — сан. Сол санды файлға жазғымыз келеді. Сұрақ: write() функциясына санды тура жазуға бола ма? Жауабы — жоқ, тікелей болмайды. Себебі write() әдісі тек жол (string) түрін ғана қабылдайды. Сан болса, алдымен оны жолға айналдыру керек.
str()write()write() әдісі файлға деректі жазады. Файлдағы барлық дерек жол (string) түрінде қабылданады, сондықтан санды жазу алдында str() функциясымен жолға түрлендіру керек. Оқыған деректі санға түрлендіру үшін int(x) немесе float(x) қолданылады.
«write() тек жол қабылдайды» — fout.write(27) деп жазсаң, Python TypeError қатесін шығарады, өйткені 27 — сан, ал write() жол күтеді. «str() — санды жолға айналдыру» — str(27) нәтижесі — "27" деген жол, енді оны write() қабылдай алады. «int(x) / float(x) — жолды санға айналдыру» — керісінше бағытта, файлдан оқылған «27» деген жолды есептеу үшін санға айналдыру қажет.
Неге дәл осылай ұйымдастырылған? Себебі файлдың ішінде сақталатын барлық дерек, түбінде, таңбалар тізбегі (мәтін). Сан мен жолдың компьютер жадында сақталу тәсілі мүлдем өзгеше, сондықтан Python оларды автоматты түрде араластырмайды.
Мысалы: a = 12, b = 15 болса, fout.write(str(a+b)) — алдымен a+b = 27 есептеледі, содан кейін str(27) = "27" жолына айналдырылып, барып файлға жазылады.
Бұл — әр түрлі валютаны айырбастауға ұқсас. Доллармен төлем жасайтын дүкенге теңгемен бара алмайсың — алдымен теңгені долларға айырбастау керек. Дәл солай, санды файлға жазу үшін алдымен оны «жол валютасына» (str()) айырбастау керек.
fout.write(a + b) деп тікелей санды жазбақ болады, нәтижесінде TypeError: write() argument must be str, not int деген қате шығады. Есте сақта: write() ішіне әрқашан str() арқылы жолға айналдырылған мән беру керек.write() әдісі тек жол қабылдайды, сондықтан санды жазу алдында str() қолдану міндетті. Керісінше, файлдан оқылған санды есептеуге қолдану үшін int() немесе float() арқылы санға айналдыру керек.Мұғалім тақтада қалай шешер еді, дәл солай қадаммен жүрейік.
fin = open("Input.txt", "r")
p = ["12", "15"], ал map(int, p) арқылы a = 12, b = 15 (енді бұлар нағыз сандар, жол емес).
p = fin.read().split() a, b = map(int, p)
fout = open("Output.txt", "w")
fout.write(str(a+b)+'\n') fout.write(str(a*b))
fin.close() fout.close()
int арқылы); ал есептеу нәтижесін файлға жазу алдында оны қайта жолға айналдыру керек (str арқылы). Және екі файлды да соңында жабуды ұмытпау керек.Бұл тақырып ҰБТ-да жиі үш түрлі формада кездеседі: (1) файлдан сандарды оқып, олармен арифметикалық амал жасау; (2) нәтижені дұрыс түрге (str) айналдырып файлға жазу; (3) дұрыс режимді ('r', 'w', 'a') таңдау.
Есте сақтау керек негізгі ережелер: файлдан оқылған дерек — әрқашан жол, есептеу алдында int()/float() қолдан; файлға жазу алдында әрқашан str() қолдан; 'w' — өшіреді, 'a' — қосады; жұмыс соңында файлды міндетті түрде close() арқылы жабу керек.
split() нәтижесін сан деп қателесіп, оларды тікелей қосу (нәтижесінде сандар емес, жолдар қосылып кетеді)write() ішіне санды str()-сіз тікелей беру (TypeError шығады)'w' режимін 'a' орнына қолданып, бар деректі байқаусызда өшіріп алуclose()) ұмытып кету- Файл — деректі тұрақты сақтайтын, атауы бар орын, ол мәтіндік немесе екілік болуы мүмкін.
- Файлмен жұмыс әрқашан үш қадаммен жүреді: ашу (
open), оқу немесе жазу, жабу (close). open()функциясында режимді ('r','w','a','b','t','+') көрсетіп, файл атауын немесе толық жолын береміз.- Оқу үшін
read(),readline()немесеread().split()қолданамыз, ал жазу үшінwrite()қолданамыз. write()тек жол қабылдайды — сандыstr()арқылы алдын ала айналдыру керек.