LEKCJA 12 – PLIKI

 

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.