ΜΥΥ105: Εισαγωγή στον Προγραµµατισµό Αρχεία Χειµερινό Εξάµηνο 2014
Διαχείριση αρχείων Ως τώρα έχουµε δει πως µπορούµε να πάρουµε την είσοδο ενός προγράµµατος από το χρήστη και πως να τυπώνουµε την έξοδό του στην οθόνη. Σε πολλές εφαρµογές, θέλουµε να πάρουµε την είσοδο ενός προγράµµατος από ένα αρχείο του υπολογιστή, ή να γράψουµε σε ένα αρχείο. Η Python παρέχει συναρτήσεις για διάβασµα και γράψιµο σε αρχεία. 2
Τύποι αρχείων Αρχεία κειµένων (text files): Περιέχουν χαρακτήρες ASCII µόνο και µπορούµε να τα διαβάσουµε ανοίγοντάς τα µε έναν απλό επεξεργαστή κειµένου (π.χ. αρχεία µε κατάληξη txt) ή τυπώνοντάς τα στην κονσόλα του λειτουργικού συστήµατος Δυαδικά αρχεία κειµένων (binary files): Περιέχουν κωδικοποιηµένη πληροφορία σε δυαδική µορφή. Δεν µπορούµε να τα διαβάσουµε µε έναν απλό επεξεργαστή κειµένου ή τυπώνοντάς τα στην κονσόλα του λειτουργικού συστήµατος 3
Που βρίσκονται τα αρχεία; Τα αρχεία αποθηκεύονται στο δίσκο του συστήµατος (δευτερεύουσα µνήµη) και η πληροφορία που γράφεται σε αυτά είναι µόνιµη παραµένει και µετά το σβήσιµο του υπολογιστή Τα αρχεία οργανώνονται σε φακέλους (folders) ή αλλιώς καταλόγους (directories) ιεραρχικά στο δίσκο Το κάθε αρχείο έχει ένα όνοµα και µια διεύθυνση µονοπατιού στο δίσκο Π.χ. όνοµα: testfile.txt, διεύθυνση µονοπατιού C:\files\testfile.txt 4
Που βρίσκονται τα αρχεία; Ένα πρόγραµµα που τρέχει στον υπολογιστή αναφέρεται σε έναν «τρέχοντα κατάλογο» Αν το πρόγραµµα δηµιουργήσει ένα αρχείο, χωρίς να προσδιορίσει το φάκελό του (δηλ. δίνοντας ένα όνοµα και όχι µια πλήρη διεύθυνση µονοπατιού) τότε το αρχείο γράφεται στον τρέχοντα κατάλογο. Επίσης, αν το πρόγραµµα ανοίγει και διαβάζει ένα αρχείο µε βάση το όνοµά του µόνο, το πρόγραµµα υποθέτει ότι το αρχείο βρίσκεται στον τρέχοντα κατάλογο 5
Διαδικασία διαχείρισης αρχείου µέσα σε ένα πρόγραµµα Άνοιξε το αρχείο Διάβασε από το αρχείο ή/και γράψε σε αυτό Κλείσε το αρχείο Το κλείσιµο δεν είναι υποχρεωτικό (µπορεί να γίνει αυτόµατα στο τέλος του προγράµµατος), αλλά µας βοηθάει να σιγουρευτούµε ότι το περιεχόµενου του αρχείου µας στο δίσκο συµφωνεί µε τις ενέργειές µας στο πρόγραµµα 6
«Άνοιγµα» ενός αρχείου Γίνεται µε τη συνάρτηση open(filename) Η συνάρτηση ανοίγει το αρχείο µε το όνοµα filename ή δίνει σφάλµα αν δεν υπάρχει αρχείο µε αυτό το όνοµα µεταβλητή που δείχνει στο αντικείµενο αρχείου >>> f = open('testfile.txt') >>> f = open('testfile') µπορούµε να δώσουµε και πλήρη διεύθυνση του αρχείου στο δίσκο (π.χ. C:\files\testfile.txt ) Traceback (most recent call last): File "<pyshell#6>", line 1, in <module> f = open('testfile') FileNotFoundError: [Errno 2] No such file or directory: 'testfile' 7
«Άνοιγµα» ενός αρχείου Το άνοιγµα ενός αρχείου αντιστοιχίζει το αρχείο σε µια µεταβλητή (αντικείµενο αρχείου) Μέσω της µεταβλητής µπορούµε να διαβάσουµε τα περιεχόµενα του αρχείου Η open παίρνει και πρόσθετα προαιρετικά ορίσµατα Αν δε βάλουµε άλλα ορίσµατα, σηµαίνει ότι ανοίγουµε το αρχείο για διάβασµα Μπορούµε επίσης να ανοίξουµε ένα αρχείο για γράψιµο, για προσθήκη δεδοµένων µόνο, για γράψιµο και διάβασµα, για γράψιµο ή/και διάβασµα δυαδικής πληροφορίας 8
«Άνοιγµα» ενός αρχείου >>> f = open('testfile.txt') >>> f = open('testfile.txt','r') >>> f = open('testfile.txt','w') >>> f = open('testfile.txt','a') >>> f = open('testfile.txt','r+') >>> f = open('testfile.txt','rb') >>> f = open('testfile.txt','rb+') άνοιγµα για διάβασµα: το ίδιο σαν να µη βάζαµε δεύτερο όρισµα άνοιγµα για γράψιµο αρχικοποιεί νέο αρχείο άνοιγµα για προσθήκη στο τέλος του αρχείου (append) διάβασµα και γράψιµο διάβασµα δυαδικού αρχείου διάβασµα και γράψιµο δυαδικού αρχείου τα + και b µπορούν να προστεθούν στα r, w και a 9
Γράψιµο σε αρχείο Μέσω της µεθόδου write >>> f = open('testfile.txt','w') >>> f.write('hello, ') 7 >>> f.write('world!') 6 >>> f.close() άνοιγµα για γράψιµο γράψε Hello, γράφτηκαν 7 χαρακτήρες «κλέισιµο» αρχείου πιστοποιεί το ότι οτιδήποτε γράψαµε θα είναι στο αρχείο στο δίσκο H f.close() χρειάζεται οπωσδήποτε στην εγγραφή γιατί µπορεί ο υπολογιστής να έχει κρατήσει τα δεδοµένα που θέλουµε να γράψουµε σε buffer και να µην τα έχει σώσει στο αρχείο. 10
Διάβασµα από αρχείο Μέσω της µεθόδου read >>> f = open('testfile.txt', 'r') >>> >>> f.read(4) 'Hell' >>> s = f.read() >>> s 'o, World!' άνοιγµα για διάβασµα διάβασε 4 χαρακτήρες επιστρέφει αυτό που διάβασε διαβάζει όλα από την τρέχουσα θέση και µετά H f.close() δεν χρειάζεται οπωσδήποτε όταν διαβάζουµε ένα αρχείο. 11
Τυχαία Προσπέλαση Μπορούµε να µετακινηθούµε σε µια συγκεκριµένη θέση του αρχείου και να διαβάσουµε, ή να γράφουµε εκέι µέσω της µεθόδου seek >>> f = open('testfile.txt','r') >>> f.seek(4) πήγαινε στη 4 θέση 4 >>> f.read(3) 'o, ' >>> f.tell() 7 επιστρέφει την τρέχουσα θέση στο αρχείο testfile.txt 12
Παράδειγµα µε seek και write Μπορούµε να µετακινηθούµε σε µια συγκεκριµένη θέση του αρχείου και να διαβάσουµε, ή να γράφουµε εκέι µέσω της µεθόδου seek >>> f = open('testfile.txt','r+') >>> f.seek(3) 3 >>> f.write('p ') 2 >>> f.seek(0) 0 >>> f.read() 'Help, World!' testfile.txt testfile.txt Help, World! 13
readline, readlines, writelines Η µέθοδος readline() διαβάζει την επόµενη γραµµή του αρχείου. Το τέλος µίας γραµµής υποδηλώνεται από το χαρακτήρα \n. >>> f = open('testfile.txt') >>> for i in range(2): print(str(i)+':', f.readline()) testfile.txt 0: 1: 14
readline, readlines, writelines Η µέθοδος readlines() διαβάζει όλες τις γραµµές του αρχείου και τις επιστρέφει σε µία λίστα. >>> f = open('testfile.txt') >>> l = f.readlines() >>> l ['\n', ''] testfile.txt Το \n είναι ειδικός χαρακτήρας που σηµαίνει «αλλαγή γραµµής» 15
readline, readlines, writelines Η µέθοδος writelines() παίρνει µία λίστα από αλφαριθµητικά και τα γράφει στο αρχείο. Πρέπει εµείς να προσθέσουµε τα \n για να δηλώσουµε που αλλαζουν οι γραµµές >>> f = open('testfile.txt') >>> l = f.readlines() >>> l[0] = 'Howdy Johnny\n' >>> f2 = open('testfile2.txt','w') >>> f2.writelines(l) >>> f2.close() testfile.txt testfile2.txt Howdy Johnny 16
Διαβάζοντας µε επαναλήψεις Μπορούµε να καλούµε τις µεθόδους read και readline επαναληπτικά µέχρι να φτάσουµε στο τέλος του αρχείου >>> f = open('testfile.txt') >>> char = f.read(1) >>> while char: print(char,end='') char = f.read(1) >>> testfile.txt ενόσω ο τρέχων χαρακτήρας που διαβάσαµε δεν είναι κενός, που σηµαίνει ότι το αρχείο δεν έχει τελειώσει 17
Διαβάζοντας µε επαναλήψεις Μπορούµε να καλούµε τις µεθόδους read και readline επαναληπτικά µέχρι να φτάσουµε στο τέλος του αρχείου >>> f = open('testfile.txt') >>> l = f.readline() >>> while l: print(l, end='') l = f.readline() >>> testfile.txt χρειάζεται, γιατί η κάθε γραµµή περιέχει το \n στο τέλος 18
Διαβάζοντας µε επαναλήψεις Το ίδιο µε while-true / break >>> f = open('testfile.txt') >>> while True: l = f.readline() if not l: break print(l, end='') >>> testfile.txt αποφεύγουµε να γράψουµε το l = f.readline() δύο φορές, άρα το πρόγραµµά µας είναι πιο ευανάγνωστο 19
Διάβασµα όλου του αρχείου (αν είναι µικρό) Μπορούµε να διαβάσουµε «όλο» το αρχείο και να εξετάσουµε τους χαρακτήρες του έναν-έναν ή τις γραµµές µία-µία >>> f = open('testfile.txt') >>> for char in f.read(): print(char, end='') >>> >>> f = open('testfile.txt') >>> for l in f.readlines(): print(l, end='') >>> 20
Διάβασµα γραµµή-γραµµή µε χρήση for Εναλλακτικός επαναληπτικός τρόπος διαβάσµατος >>> f = open('testfile.txt') >>> for l in f: print(l,end='') για κάθε γραµµή l που διαβάζεται από το αρχείο (το read εδώ υπονοείται) testfile.txt >>> for l in open('testfile.txt'): print(l,end='') πιο σύντοµος τρόπος, αλλά δεν µπορούµε να κάνουµε close. Το close θα γίνει µετά το τέλος του προγράµµατος/συνάρτησης 21
list(open(filename)) Μπορoύµε να µετατρέψουµε τα περιεχόµενα του αρχείου σε λίστα χρησιµοποιώντας list(open(filename)) Αντίστοιχα µε το list(range(5)) >>> l = list(open('testfile.txt')) >>> l ['\n', ''] testfile.txt 22
Παράδειγµα >>> f = open('testfile2.txt','w') >>> f.write('first line\n') 11 >>> f.write('second line\n') 12 >>> f.write('third line\n') 11 >>> f.close() >>> first, second, third = open('testfile2.txt') >>> first 'First line\n' >>> second 'Second line\n' >>> third 'Third line\n' ανοίγει το αρχείο και διαβάσει τις γραµµές στις µεταβλητές ταυτόχρονα 23
Άσκηση Γράψτε µια συνάρτηση, η οποία θα παίρνει σαν όρισµα ένα όνοµα αρχείου και ένα αλφαριθµητικό και θα επιστρέφει πόσες φορές εµφανίζεται το αλφαριθµητικό µέσα στο αρχείο π.χ. stringcount('testfile.txt','you') = 1 def stringcount(filename, s): f = open(filename) content = f.read() return content.count(s) testfile.txt διαβάζει όλο το αρχείο και βάζει τα περιεχόµενά του στο αλφαριθµητικό content 24
Άσκηση Γράψτε µια συνάρτηση, η οποία θα παίρνει σαν όρισµα ένα όνοµα αρχείου και θα επιστρέφει τον αριθµό των λέξεων σε αυτό π.χ. wordcount('testfile.txt') = 5 def wordcount(filename): f = open(filename) content = f.read() return len(content.split()) testfile.txt 25
Άσκηση Γράψτε µια συνάρτηση, η οποία θα παίρνει σαν όρισµα ένα όνοµα αρχείου και θα επιστρέφει τις λέξεις του σε µια λίστα, χωρίς σηµεία στίξης (!,.:;?) π.χ. words('testfile.txt') = ['Hello', 'World', 'How', 'are', 'you'] def words(filename): f = open(filename) content = f.read() lout = [] for s in content.split(): chars = list(s) l = [] for c in chars: if c not in '!,.:;?': l.append(c) lout.append(''.join(l)) return lout testfile.txt 26
Άσκηση Γράψτε µια συνάρτηση, η οποία θα παίρνει σαν όρισµα ένα όνοµα αρχείου και θα επιστρέφει τις λέξεις του σε µια λίστα, χωρίς σηµεία στίξης (!,.:;?) π.χ. words('testfile.txt') = ['Hello', 'World', 'How', 'are', 'you ] Με χρήση translate def words(filename): trantab = str.maketrans('!,.:;?', ' f = open(filename) content = f.read() newcontent = content.translate(trantab) return newcontent.split() ') testfile.txt δηµιουργεί πίνακα µετάφρασης trantab, που αντιστοιχίζει κάθε σηµείο στίξης σε ένα διάστηµα «µεταφράζει» το content µε βάση το trantab 27
Άσκηση Γράψτε µια συνάρτηση, η οποία θα παίρνει σαν όρισµα ένα όνοµα αρχείου και ένα αλφαριθµητικό και θα τυπώνει τις γραµµές του αρχείου που περιέχουν το αλφαριθµητικό π.χ. grep('testfile.txt','are') >>> def grep(filename, w): for l in open(filename): if w in l: print(l,end='') testfile.txt 28
close και flush Όταν ανοίγουµε ένα αρχείο για γράψιµο και γράφουµε σε αυτό, οι αλλαγές στο αρχείο γίνονται πρώτα στη µνήµη του υπολογιστη: δεν υπάρχει εγγύσηση ότι το αρχείο στο δίσκο έχει αλλάξει. Η f = open( filename, w ) δε δηµιουργεί το αρχείο στο δίσκο απ ευθείας Η f.write( something ) δεν γράφει απ ευθείας στο αρχείο του δίσκου Οι αλλαγές γίνονται σε ένα buffer της µνήµης Η f.close() γράφει όλα τα δεδοµένα του buffer στο αρχείο και κλείνει το αρχείο Η f.flush() γράφει όλα τα δεδοµένα του buffer στο αρχείο χωρίς να το κλείσει 29
Άσκηση: openlog Γράψτε µια συνάρτηση, openlog() η οποία θα ανοίγει ένα αρχείο (όπως η open()) και θα καταγράφει σε ένα αρχείο log.txt το ιστορικό των ανοιγµάτων αρχείων µέσω της openlog() Παράδειγµα επιθυµητής συµπεριφοράς: >>> f = openlog('testfile.txt','r ) log.txt Wednesday Dec/03/14 12:38 PM: File testfile.txt opened. 30
Άσκηση: openlog, βήµα 1 Ας αρχίσουµε από το βασικό: θέλουµε η openlog() να κάνει ότι και η open() : def openlog(filename, mode): f = open(filename, mode) return f Είναι εντάξει το παραπάνω; ΟΧΙ: def openlog(filename, mode = 'r'): f = open(filename, mode) return f 31
Άσκηση: openlog, βήµα 2 Θέλουµε η openlog() να γράφει στο τέλος του αρχείου log.txt το ότι ανοίξαµε το αρχείο: def openlog(filename, mode='r'): f = open(filename, mode) logfile = open('log.txt', 'a') logfile.write('file %s opened.\n' % filename) logfile.close() return f Αυτό που µένει είναι να γράψουµε το χρόνο 32
time module Το module time έχει µεθόδους προσπέλασης του χρόνου >>> import time >>> time.time() 1417606322.112668 >>> time.gmtime(0) time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=0) >>> time.localtime() epoch τοπική ώρα η µέθοδος time() επιστρέφει τον αριθµό των δευτερολέπτων που έχουν περάσει από τη στιγµή epoch epoch: 00:00:00 of Jan. 1, 1970 time.struct_time(tm_year=2014, tm_mon=12, tm_mday=3, tm_hour=13, tm_min=37, tm_sec=35, tm_wday=2, tm_yday=337, tm_isdst=0) 33
time module Η µέθοδος strftime µετατρέπει ένα αντικείµενο χρόνου σε ένα κατανοητό αλφαριθµητικό >>> time.strftime('%a %b/%d/%y %I:%M %p', time.localtime()) 'Tuesday Mar/16/10 02:06 PM' 34
time module Η µέθοδος strftime µετατρέπει ένα αντικείµενο χρόνου σε ένα κατανοητό αλφαριθµητικό 35
Άσκηση: openlog, βήµα 3 Θέλουµε η openlog() να γράφει στο τέλος του αρχείου log.txt το ότι ανοίξαµε το αρχείο και πότε το κάναµε: def openlog(filename, mode='r'): import time f = open(filename, mode) logfile = open('log.txt', 'a') opentime = time.strftime('%a %b/%d/%y %I:%M %p', time.localtime()) logfile.write('%s: File %s opened.\n' % (opentime, filename)) logfile.close() return f 36