Do tej pory zajmowaliśmy się wyłącznie przechowywaniem danych w pamięci operacyjnej komputera. Pamięć operacyjna komputera jest jednak ulotna. Aby zabezpieczyć dane należy zapisać je w pliku dyskowym.
Jeżeli w trybie interaktywnym Pythona wpiszemy:
>>> f1
= open("plik1.txt","wb")
– spowodujemy stworzenie i otwarcie do zapisu pliku "plik1.txt" w aktualnym katalogu dyskowym (po uruchomieniu IDLE’a jest to katalog, w którym zainstalowano Pythona, domyślnie „C:\Python24”. Choć zapisywać będziemy w pliku sam tekst, używamy trybu binarnego, w celu uniknięcia problemu z ustalaniem bieżącej pozycji w pliku.
Obiekty plikowe mają trzy podstawowe atrybuty:
>>> f1.name
'plik1.txt'
>>> f1.mode
'w'
>>> f1.closed
False
Pliki obsługujemy przy użyciu następujących metod:
>>> f1.write("Początek
pliku")
Możemy teraz, korzystając z Eksploratora Windows przejść do katalogu, w którym znajduje się plik (przypominam, standardowo ścieżką dostępu będzie „C:\Python24\plik1.txt”) i otworzyć go w Notatniku. Plik powinien znajdować się na swoim miejscu, jednak prawdopodobnie będzie pusty. Winne oczywiście jest buforowanie.
>>> f1.flush()
Jeżeli teraz ponownie otworzymy „plik1.txt” w Notatniku, powinniśmy zobaczyć następującą zawartość:
Początek pliku
Metoda write nie kończy zapisanych danych znakiem końca linii. By przejść do kolejnej linii, musimy sami zapisać taki znak (\n):
>>> f1.write("\nDruga
linia")
>>> f1.close()
Normalne zakończenie programu powoduje automatyczne zamknięcie wszystkich otwartych plików, jednak programiści powinni samodzielnie zamykać wszystkie pliki, które otwarli.
Jeżeli teraz ponownie otworzymy „plik1.txt” w Notatniku (oczywiście poprzednią wersję, jeżeli nadal jest otwarta, należy już zamknąć, gdyż Notatnik nie aktualizuje zawartości edytowanego dokumentu po jego otwarciu z dysku), powinniśmy zobaczyć następującą zawartość:
Początek pliku
Druga linia
Spróbujemy teraz otworzyć zapisany przed chwilą plik do modyfikacji:
f1 =
open("plik1.txt","r+b")
>>> print f1.read()
Początek pliku
Druga linia
>>> f1.tell()
26L
>>> f1.seek(0)
Modyfikujemy zawartość pliku zapisując na istniejącej wcześniej pozycji:
>>> f1.write("Pierwsza
linia")
Aby przesunąć pozycję pliku nie na pozycję wyrażoną absolutnie (od początku pliku), lecz względnie (od aktualnej pozycji), jako drugi parametr podajemy 1:
>>> f1.seek(-14,1)
Możemy wczytywać tylko fragment zawartości pliku o określonej długości:
>>> print f1.read(14)
Pierwsza linia
Aby przesunąć pozycję pliku względem jego końca, jako drugi parametr podajemy 2:
>>> f1.seek(0,2)
>>>
f1.writelines(["\n3 linia","\n4 linia","\n5
linia"])
>>>
f1.seek(0)
>>>
a=f1.readlines()
>>> print a
['Pierwsza linia\n', 'Druga linia\n',
'3 linia\n', '4 linia\n', '5 linia']
Zauważmy, że readlines wykorzystuje znaki końca linii do podziału tekstu na napisy, nie usuwa ich jednak automatycznie.
>>>
f1.truncate(26)
>>>
f1.seek(0)
>>>
print f1.read()
Pierwsza linia
Druga linia
>>> f1.isatty()
False
Przykładami takich plików są sys.stdout i sys.stdin (pamiętajmy przy tym, że są to strumienie kierujące dane z/do konsoli, stąd nie wszystkie operacje są dla nich dostępne):
>>>
import sys
>>>
sys.stdout.isatty()
True
Należy pamiętać, że użytkownik uruchamiając program może przekierować jego wejście i wyjście z poziomu systemu operacyjnego. Można to sprawdzić właśnie dzięki metodzie isatty – jeżeli dla któregoś z podanych plików zwraca ona wartość False, wejście lub wyjście zostało przekierowane do zwykłego pliku.
Atrybuty sys.stdout i sys.stdin są zmiennymi, można więc zmienić je na dowolny inny plik, przekierowując w ten sposób wyjście/wejście wewnątrz programu:
>>>
import sys
>>>
ekran=sys.stdout
>>>
sys.stdout = open("wyjscie.txt","w")
>>> print
"Cokolwiek"
>>> print "Gdzie to się
wyświetliło?"
>>>
sys.stdout=ekran
>>>
print open("wyjscie.txt","r").read()
Cokolwiek
Gdzie to się wyświetliło?
Co więcej, obiekty plikowe w Pythonie wcale nie muszą być połączone z jakimikolwiek plikami fizycznymi. Wystarczy tylko, że należą do klasy posiadającej używane metody. Można to wykorzystać np. do formatowania danych wyświetlanych instrukcją print:
>>>
class centrowanie:
def write(self, s):
ekran.write(s.center(60))
>>>
sys.stdout=centrowanie()
>>> print
"Cokolwiek"
Cokolwiek
>>> print "O! Jak
ładnie"
O! Jak ładnie
>>> sys.stdout=ekran
>>> print "Już
normalnie!"
Już normalnie!
Przykład 1. Program, który kopiuje plik o nazwie podanej przez użytkownika, wydłużając nazwę nowego pliku o prefiks „kopia”.
Rozwiązanie z komentarzem:
n=raw_input("Podaj pełną nazwę
pliku do skopiowania>")# n – nazwa oryginału
oryg = file(n,"rb") # otwieramy oryginał do odczytu
kop = file("kopia
"+n,"wb")# otwieramy kopię do zapisu
while True: # powtarzamy
b
= oryg.read(1) # wczytujemy 1 bajt z
oryginału
if
not b: break # nic się nie wczytało?
Koniec pliku!
kop.write(b) # zapisujemy 1 bajt do kopii
kop.close() # zamykamy kopię
oryg.close() # zamykamy oryginał
print "Kopiowanie zakończone
pomyślnie" # komunikat końcowy
Przykład uruchomienia:
>>>
================================ RESTART ==============================
>>>
Podaj pełną nazwę pliku do
skopiowania>plik1.txt
Kopiowanie zakończone pomyślnie
Przykład 2. Program „cezar.py”, który szyfruje wskazany przez użytkownika plik tekstowy w oparciu o szyfr Cezara (przesuwanie liter w alfabecie o podaną wartość).
Rozwiązanie z komentarzem:
t=raw_input("Podaj pełną nazwę
pliku >")
p=input("Podaj przesunięcie >”)
f1 = open(t,"r+b") # plik otwarty do modyfikacji
s=f1.read() #
wczytujemy do s tekst źródłowy
sz="" # sz oznacza
tekst zaszyfrowany
for c in s: # dla każdego znaku w 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
Wypróbujmy:
>>>
================================ RESTART =============================
>>>
Podaj pełną nazwę pliku >plik1.txt
Podaj przesunięcie >3
Przyjrzyjmy się teraz (w notatniku) zawartości pliku plik1.txt po zaszyfrowaniu:
Slhuzv}d olqld
Guxjd olqld
Aby rozszyfrować plik należy jeszcze raz uruchomić program „cezar.py”, i podać jako przesunięcie ujemną wartość liczby podanej przy szyfrowaniu:
>>>
================================ RESTART =============================
>>>
Podaj pełną nazwę pliku >plik1.txt
Podaj przesunięcie >-3
Przyjrzyjmy się teraz zawartości pliku plik1.txt po odszyfrowaniu:
Pierwsza linia
Druga linia
Ćwiczenie I. Napisz program „type.py”, który wyświetli na ekranie zawartość pliku o nazwie podanej przez użytkownika.
Ćwiczenie II. Napisz program „lista.py”, który:
a. a. Jeżeli na dysku nie ma pliku „lista.txt”, wczyta od użytkownika listę studentów (imię, nazwisko, grupa) i zapisze ją do pliku „lista.txt”
b. b. Jeżeli na dysku jest już plik „lista.txt”, wczyta z niego listę studentów (imię, nazwisko, grupa) , a użytkownikowi umożliwi dopisywanie nowych studentów do listy, na koniec zapisze listę z powrotem do pliku.
Ćwiczenie III. Napisz program „losuj_plik.py”, który wczyta od użytkownika trzy liczby całkowite: a, b i n, a następnie wygeneruje plik, zawierający n linii, z których w każdej znajdzie się losowa liczba całkowita z zakresu od a do b. W różnych liniach mają znaleźć się różne liczby, jednak ta sama liczba może występować w pliku więcej niż raz.
Ćwiczenie IV. Napisz program „losuj_plik2.py”, różniący się od programu z ćwiczenia III tym, że w całym pliku określona liczba może wystąpić tylko jeden raz. Plik nie może mieć przy tym więcej linii, niż wynosi długość zakresu od a do b.