Komunikacja człowiek - komputer Wykład 3 Pliki i bazy danych w Pythonie Literatura: Jakub Swacha – kurs Pythona http://uoo.univ.szczecin.pl/~jakubs/ Marcin Młotkowski – kurs języka Python http://www.ii.uni.wroc.pl/~marcinm/dyd/python/ Python 2.6.4 documentation http://docs.python.org/ Opracował: dr inż. Wojciech Bieniecki wbieniec@kis.p.lodz.pl http://wbieniec.kis.p.lodz.pl Katedra Informatyki Stosowanej Politechnika Łódzka
Otwieranie plików Otwarcie i zamknięcie pliku: f = open('plik', 'r') Atrybuty: 'r' – do odczytu 'w' – do zapisu 'a' – do ‘appendu’ 'r+' – do odczytu i zapisu 'rb', 'wb', 'ab' – odczyt i zapis binarny f.close() – zamyka plik
Atrybuty obiektu plikowego Obiekty plikowe mają trzy podstawowe atrybuty: name zawiera nazwę pliku (tak jak podano ją przy otwarciu) >>> f1.name 'plik1.txt' mode określa tryb, w jakim otwarto plik >>> f1.mode 'w' closed określa czy plik jest zamknięty >>> f1.closed false
Błędy i wyjątki – otwarcie nieistniejącego pliku >>> f = open("plik", "r") Traceback (most recent call last): File "<stdin>", line 1, in ? IOError: [Errno 2] No such file or directory: 'plik' Plik nie istnieje i dlatego zostanie rzucony wyjątek IOError. Ponieważ nie przechwytujemy tego wyjątku, Python po prostu wypisuje błąd i zakańcza działanie programu. >>> try: ... fsock = open("c:/niemapliku.txt") ... except IOError: ... print "Plik nie istnieje" ... print "Ta linia zawsze zostanie wypisana" Plik nie istnieje Ta linia zawsze zostanie wypisana
Czytanie pliku tekstowego f.read() – odczyt całego pliku f.read(l_zn) – odczyt tylko l_zn znaków. Zwracany jest string f.readline() – odczytuje jeden wiersz. Zwracamy razem ze znakiem "\n" f.readlines() – zwraca listę wierszy
Obsługa błędów czytania try: f = open(filename, "rb", 0) f.seek(-128, 2) tagdata = f.read(128) finally: f.close() except IOError: pass IOError może być rzucony przez: - open (plik może nie istnieć), - seek (plik może być mniejszy niż 128 bajtów) - read (być może dysk posiada uszkodzony sektor) kod z bloku finally zostanie zawsze wykonany, nawet jeśli jakaś instrukcja bloku try rzuci wyjątek. Pass jest wyrażeniem Pythona, które nic nie robi.
Przykłady czytania pliku f = open('test.py', 'r') while True: wiersz = f.readline() if len(wiersz) == 0: break print wiersz, f.close() f = open('test.py', 'r') for wiersz in f: print wiersz, words = open("c:/730.txt").read().split() print words[:30] print words.count("Oliver") print words.count("Twist") print len(set(words))
Przykład: czytanie TAG z MP3 f = open("Feel.mp3","rb") print f.tell() f.seek(-128, 2) tagData = f.read(128) print tagData tell zwraca aktualną pozycję w otwartym pliku. seek służy do poruszania się po otwartym pliku. Drugi argument: 0 – pozycja bezwzgledna, 1 – względem pozycji aktualnej 2 – względem końca read czyta określoną liczbę bajtów z otwartego pliku i zwraca dane w postaci łańcucha znaków, które zostały odczytane. Opcjonalny argument określa maksymalną liczbę bajtów do odczytu. Jeśli nie zostanie podany argument, read będzie czytał do końca pliku.
Zapis do pliku Plik musi być otwarty w trybie do zapisu lub odczytu i zapisu 'w', 'a', 'r+' f.write(string) zapisuje zawartość łańcucha string ale nic nie zwraca >>> f.write('This is a test\n') Aby zapisać dane innego typu muszą być skonwertowane na string value = ('the answer', 42) s = str(value) f.write(s) f = ('/tmp/workfile', 'r+') f.write('0123456789abcdef') f.seek(5) print f.read(1) #wypisze 5 f.seek(-3, 2) #3 bajt przed końcem f.read(1) #wypisze d
Kopiowanie pliku n=raw_input("Podaj pełną nazwę pliku do skopiowania>") oryg = file(n,"rb") kop = file("kopia "+n,"wb")# otwieramy kopię do zapisu while True: b = oryg.read(1) # wczytujemy 1 bajt z oryginału if not b: break # Koniec pliku! kop.write(b) kop.close() oryg.close() print "Kopiowanie zakończone pomyślnie"
Kodowanie pliku t=raw_input("Podaj pełną nazwę pliku >") p=input("Podaj przesunięcie >”) f1 = open(t,"r+b") s=f1.read() sz="" # sz oznacza tekst zaszyfrowany for c in s: a=ord(c) # wyliczamy kod ASCII if a > 32: # znaków białych i sterujących nie szyfrujemy c=chr((a+p) % 256) # inne przesuwamy sz+=c # dodajemy do sz f1.seek(0) # ustawiamy pozycję pliku na jego początku f1.write(sz) # zapisujmy sz f1.close() # zamykamy plik
Zapisywanie całych wierszy lista = ["napis1", "napis 2", "napis 3"] g=open("test.txt","w") g.writelines(lista) #zapisuje do pliku listę, oddziela znakiem " " g.close() f.writelines(['to\n', 'są\n', 'kolejne\n', 'wiersze\n'])
Pliki i struktury: MP3 TAG
Obsługa pliku *.ini
Obsługa pliku *.ini import ConfigParser import sys config = ConfigParser.ConfigParser() config.add_section("book") config.set("book", "title", "the python standard library") config.set("book", "author", "fredrik lundh") config.add_section("ematter") config.set("ematter", "pages", 250) config.write(sys.stdout) [book] title = the python standard library author = fredrik lundh [ematter] pages = 250
Obsługa pliku *.ini – zmiany Modyfikacja parametrów: ini.set('window', 'height', 100) Usuwanie: ini.remove_option('window', 'height') ini.remove_section('window') Zapis konfiguracji f = open('konfig.ini', 'w') ini.write(f) fh.close()
Obsługa plików CSV CSV – Comma Separated Values Dane "Anna", "Kowalska", 2000-01-01, 3 "Jan", "Nowak", 2006-04-01, 2 Notowania giełdowe 2006-04-26;1415.79;183.29;102.14; 2006-04-25;1415.88;183.43;102.31; Parametry formatu: delimiter – separator, np. ',' ';' ':‘ lineterminator – koniec wiersza quotechar – znak cudzysłowu quoting – kiedy ujmować pola w cudzysłów:QUOTE_ALL, QUOTE_NONNUMERIC, QUOTE_NONE
Odczyt i zapis pliku CSV import csv reader = csv.reader(open('/etc/passwd', 'r'), delimiter=':', quoting=csv.QUOTE_NONE) for row in reader: print row import csv data = [ [1, 'Kubus'], [2, 'Puchatek'] ] writer = csv.writer( open('out', "w"), dialect=csv.excel) writer.writerows(data)
CSV - Wykorzystanie słowników fh = open('notowania.csv', "r") reader = csv.DictReader(fh, delimiter=';') for row in reader: for k in row.keys(): print k, row[k] Własne klucze: fh = open('notowania.csv', "r") klucze = ['lp', 'name'] reader = csv.DictReader(fh, fieldnames= klucze) for row in reader: print row['lp'], row['name']
Pliki rekordowe Plik Rekord Rekord Indeks(int) Imię (char[20] Nazwisko (char[30]) Ocena (float) Semestr(byte) Grupa(char[5])
Plik rekordowy – użycie struct import struct f=open("studenci","wb") imie="Jan" nazwisko="Kowalski" indeks=70678 ocena=4.5 semestr=3 grupa="3D20" rekord=struct.pack("<L20s30sfb5s",indeks,imie,nazwisko,ocena,semestr,grupa) f.write(rekord) f.close()
Struct – znaczenie symboli Format Typ języka C Python x pad byte brak wartości c char napis o długości 1 b signed char integer B unsigned char h short H unsigned short i int I unsigned int long l L unsigned long q long long Q unsigned long long f float d double s char[] string p P void *
Znaczenie pierwszego znaku Porządek bajtów Rozmiar i wyrównanie @ odpowiedni dla maszyny = standardowy < little-endian > big-endian ! sieciowy (= big-endian) Jeśli pierwszym znakiem napisu nie jest żaden z powyższych, przyjmuje się interpretację odpowiadającą znakowi "@". Porządkiem bajtów odpowiednim dla maszyny może być zarówno big-endian jak i little-endian, w zależności od systemu, na którym wykonywany jest program. Przykładowo, procesory firm Motorola oraz Sun używają porządku bajtów big-endian; procesory firm Intel oraz DEC używają little-endian.
Odczyt pliku rekordowego g=open("studenci","rb") sr=struct.calcsize("<L20s30sfb5s") while True: rek = g.read(sr) if not rek: break indeks,imie,nazwisko,ocena,semestr,grupa=\ struct.unpack("<L20s30sfb5s",rek) print indeks,imie,nazwisko,ocena,semestr,grupa g.close()
Serializacja obiektów Serializacja obiektu polega na przekształceniu danych go opisujących w ciąg bajtów (funkcja dumps), z którego można później odtworzyć taki sam obiekt (funkcja loads).
Serializacja własnych obiektów Dzięki pickle można serializować obiekty należące do klas zdefiniowanych przez nas. class wymiary3: x=0; y=0; z=0 w3=wymiary3() w3.x=1; w3.y=2; w3.z=3 zapis=pickle.dumps(w3) del w3 w3=pickle.loads(zapis) print w3.x; w3.y; w3.z
Zapis bezpośrednio do pliku f1=file("trzy_rzeczy.txt","w+") pickle.dump((lista,slownik,w3),f1) lista=[]; slownik={}; w3=wymiary3() print lista; slownik; w3.x [] {} f1.seek(0) (lista,slownik,w3)=pickle.load(f1) print lista; slownik; w3.x [1, 2, 'trzy', 4] {'a': 'b', 1: 2} 1
Moduł dumbdbm Moduł tworzy słownik zapisany na dysku. Składa się on z dwóch plików „.dat” i indeksującego „.dir”). Obsługa bazy jest identyczna jak obsługa słownika, z tą różnicą, że wszystkie zachowane w niej dane przechowywane są nie w pamięci, lecz na dysku. import dumbdbm db=dumbdbm.open("prosta_baza") db['napis']="hej ho!" print db['napis'] db.close() Bazy danych typu dbm pozwalają używać napisów jako kluczy i wartości. Próba zachowania w niej obiektu innego niż napis typu, nieuchronnie kończy się błędem
Moduł shelve analogiczny sposób dostępu do danych (podobny słownikowi), umożliwiając jednak zachowywanie obiektów dowolnego typu (nie tylko napisów) import shelve lista = [1, 2, "trzy", 4] slownik={"a":"b",1:2} db = shelve.open ('baza') db['lista']=lista db['slownik']=slownik
Moduł shelve - możliwości liczba elementów: >>> len(db) 2 Sprawdzenie istnienia klucza: >>> 'lista' in db True Lista kluczy: >>> db.keys() ['lista', 'slownik']
Moduł shelve - możliwości Wyszukanie wartości po kluczu >>> db['lista'] [1, 2, 'trzy', 4] >>> db['slownik'] {'a': 'b', 1: 2} Lista wartości: >>> db.values() [[1, 2, 'trzy', 4], {'a': 'b', 1: 2}] Lista elementów: >>> db.items() [('lista', [1, 2, 'trzy', 4]), ('slownik', {'a': 'b', 1: 2})]
Moduł shelve - możliwości Modyfikacja wartości: >>> db['lista']=[3,2] Usunięcie elementu: >>> del db['lista'] >>> db.items() [('slownik', {'a': 'b', 1: 2})] Usunięcie wszystkich elementów: >>> db.clear() >>> db.items() [] Zamknięcie bazy >>> db.close()
Baza danych SQLite SQLite to biblioteka napisana w języku C Obsługuje "lekką" bazę danych w postaci jednego pliku na dysku. Nie wymaga instalacji serwera ani łączenia się z serwerem. Używa odmiany języka SQL Może być używana jako struktura danych skojarzona z aplikacją Możliwe jest tworzenie wstępnej wersji aplikacji z wykorzystaniem SQLite, a następnie przeniesienie jej na standardowy serwer bazy danych (PostgreSQL czy Oracle) Implementuje DB API 2.0 z rozszerzeniami
Proste operacje na bazie import sqlite3 db = sqlite3.connect('temp.db') kursor = db.cursor() kursor.execute("create table Student(nazwisko text, imie text, indeks int, ocena real)") db.commit() kursor.execute("insert into Student values('Kowalski' , 'Jan' , 70660, 4.5)") kursor.execute('SELECT * FROM Student') for row in kursor: print row kursor.close()
Zapytanie sparametryzowane Czasem zapytanie będzie wykorzystywać zmienne z programu. Sklejanie zapytania poprzez użycie operacji na stringach w Pythonie może być niebezpieczne (narażenie na atak Injection). W zamian należy użyć symbol zastępczy. # NIE! – niebezpieczne nazwisko = 'Kowalski' kursor.execute("select * from Student where nazwisko = '%s' " % nazwisko) # TAK! t = (nazwisko,) kursor.execute('select * from Student where nazwisko=?', t) # Bardziej złożony przykład for t in [('Kowalski', 'Jan', 70123, 4.5), ('Wisniewski', 'Maciej', 143245, 3.5), ('Nowak', 'Grzegorz', 132322, 3), ]: kursor.execute('insert into Studencivalues (?,?,?,?)', t)
SQLite w pamięci i generatory import sqlite3 def char_generator(): import string for c in string.letters[:26]: yield (c,) con = sqlite3.connect(":memory:") cur = con.cursor() cur.execute("create table characters(c)") cur.executemany("insert into characters(c) values (?)", char_generator()) cur.execute("select c from characters") print cur.fetchall()
„Prawdziwe” bazy danych Python obsługuje różne serwery relacyjnych baz danych między innymi: Oracle DB/2 MySQL PostgreSQL MS SQL Python Database API Specification Zunifikowany interfejs (metody i pola) dostępu do różnych silników relacyjnych baz danych (Aktualna wersja: 2.0)
Korzystanie z MySQL import MySQLdb db = MySQLdb.connect(host='localhost', db='studenci', user='root', passwd='root') wynik = db.cursor() wynik.execute('SELECT * FROM Student') row = wynik.fetchone() while row: print row wynik.close() db.close()