Zapis i odczyt plików

vegat

Ten artykuł ma za zadanie zaprezentować większość aspektów dotyczących operacji na plikach, a dokładni na ich odczycie i zapisie. Jest to kolejny artykuł z serii dla bardzo początkujących jeśli chodzi o świat Pascala ;) Pascal nie udostępnia przytłaczającej liczby możliwości, jeśli chodzi o zapis/odczyt plkiów. Jeszcze jedno: do zrozumienia niniejszego artykułu niezbędna jest przynajmniej podstawowa wiedza o zmiennych, tablicach, ew. o haszach (tablicach wielowymiarowych), oraz o rekordach.

STARTUJEMY

Naszym pierwszym programem będzie taki, który umożliwi nam zapisanie wprowadzonego przez użytkownika tekstu, oraz wczytanie i wyświetlenie go. Wykorzystamy w tym celu najprostszą metodę:

program test1;
{(c) vXc SOFTWARE 2004 - www.vxcprogramming.prv.pl}
{written by Vegat}

var
    s:string; {w niej przechowamy dane}
    plik:Text; {zmienna, w ktorej przechowujemy uchwyt pliku tekstowego}

begin
    s:='';
    WriteLN('Odczyt czy zapis? [o/z]'); {prosimy o wybranie, czy chcemy odczytać, czy zapisać do pliku}
    ReadLN(s); {wczytujemy ciag znakow (mozna tez tak: s[1]:=readkey)}
    case s[1] of
        'o': begin {jest 'o',odczytujemy:)}
            Assign(plik,'test.txt'); {przypisujemy plik do uchwytu}
            Reset(plik); {otwieramy do ODCZYTU}
            ReadLN(plik,s); {wyciagamy pierwsza linia z pliku}
            WriteLN('W pliku jest zapisane:');
            WriteLN(s); {wyswietlamy zawartosc zmiennej}
            Close(plik); {zamykamy plik}
        end; {koniec bloku 'o' - Odczyt}
        'z': begin {zapis}
            Assign(plik,'test.txt'); {przypisanie j/w}
            Rewrite(plik); {czyscimy plik, lub go tworzymy, jak go nie ma}
            WriteLN('Podaj, co mam zapisac do pliku:'); {prosimy o wpisanie tresci}
            ReadLN(s);
            Write(plik,s+#13); {zapisujemy do pliku, o tym #13 za chwile}
            Close(plik); {zamykamy plik}
        end; {koniec bloku zapisu}
    end; {koniec case}
    readLN; {wstrzymujemy program}
end. {koniec programu}

Uffff..... Tak, kawał kodu, no nie? Jak na podstawy to dużo.
Wyjaśnienie nieścisłości i tego, co nie zmieściło się w komentarzu:
-o funkcji case przeczytasz w innym artykule, wiec tu jej nie opisze;

-Funkcja [b]Assign[/b]: Służy ona do przypisania pliku fizycznie będącego na dysku do zmiennej, która jest jego uchwytem. Dzięki temu odwołując się do zmiennej plik, modyfikujemy plik na dysku.
Jeśli w funkcji nie podamy ścieżki, to plik zostanie utworzony w katalogu, w którym się aktualnie znajduje aplikacja (plik *.exe). Plik nie musi się nazywać test, ba może mieć nawet inne rozszerzenie. Będzie po prostu traktowany jak plik tekstowy. A przecież nawet exeki da się otworzyć w notatniku. Możesz nadać im fajną końcówkę, np. *.dtb lub nawet *.dll. Wygląda to profesjonalnie, nie? :).

-Otwarcie pliku: aby otworzyć plik, musimy się zdecydować, czy chcemy czytać, czy zapisywać:
Do poszczególnych są oddzielne funkcje: [b]Reset[/b] - do odczytu, [b]Rewrite[/b] - wyczyszczenie, lub w przypadku braku - utworzenie pliku i [b]Append[/b] - otwarcie pliku w celu dopisywania do istniejącej już zawartości.

-Zapis/odczyt z pliku realizuemy za pomocą poleceń Read(LN) oraz Write(LN), z tym, że w przeciwieństwie do wyświetlania na monitorze, musimy najpierw podać uchwyt pliku.

-Funkcja Close(plik:Text) zamyka plik. Jeżeli go nie zamkniemy pozbawimy inne programy możliwości jego edycji.

Podany wyżej kod sprawdza się tylko przy odczycie pojedynczych linii z pliku. Sprawdź to. Otwórz za pomocą notatnika plik test.txt (czy jak go tam nazwałeś) i dopisz dodatkową linię. Uruchom nasz programik, wybierz odczyt. Zobaczysz TYLKO PIERWSZĄ LINIĘ. Jak odczytać cały plik i wyświetlić go na ekranie? Musimy wstawić pętle. Najlepsze do tego są pętle REPEAT i WHILE, o których możecie przeczytać w artykule 'Pętle w Pascalu'. potrzeby jest nam warunek. Możemy to zrobić po "chłopsku", tzn. sprawdzać, czy odczytany wiersz nie jest pusty. To ma jedną wadę: co będzie gdy będziemy mieli taki plik:
pierwsza linia pliku
druga linia pliku
trzecia linia pliku

piąta linia pliku (czwartą ktoś zeżarł)

Odczytane zostaną tylko trzy pierwsze linie. Aby tego doświadczyć, napiszemy kod:

{napisz sobie swoja procedurke zapis/odczyt}

{...}
while s<>'' do 
    begin
        readLN(plik,s);
        WriteLN(s);
    end;

{...}

{dalszy ciąg też sobie dopisz :)}

Jak odczytać taki plik? Ano, na szczęście Pascal ułatwia nam zadanie dając funkcję eof(plik:Text), która zwraca true, gdy plik się zakończy. Jak by to wyglądało z powyższym kodem? Proste:

{...}
while not eof(plik) do {dopoki nie koniec pliku, wtedy odczytaj linie i ja wypisz} 
    begin
        readLN(plik,s);
        WriteLN(s);
    end;

{...}

Podsumowując, zaprezentuje kod, który umożliwia dostep do pliu po podaniu hasła i loginu, które są zapisane w pliku. Jest to bardzo proste do złamania (otwórz plik w notatniku) ale bardzo edukacyjne. Kod ten był od pewnego czasu dostęny w download/pascal/kody źródłowe , lecz tu także się zaprezentuje:

  1. Tworzymy plik dane.dtb o takiej przykładowej treści :
kowalski
k0v^l5ky

 [==============+ FILE INFO +==============]
 ||                                                                                 ||
 ||       Plik pochodzi ze strony:                                        ||
 ||    =< www.vxcprogramming.prv.pl >=                         ||
 ||    Serwis poświęcony programowaniu                           ||
 ||                                                                                 ||
 ||     (c) 2004 vXc SOFTWARE - Vegat                              ||
 ||                                                                                  ||
 \\                                                                                  //
  \=====================================/

Potrzebny nam teraz program: oto cały jego kod, z komentarzami. Dla leniwych kod jest w pliku ze źródłami do artykułu:)

Uses CRT;
{(c) copyright 2004 vXc SOFTWARE
 *** written by Vegat

Program za pomoca pliku przechowuje poufne dane
}
var
user,passwd,us,ps:String; {troche zmiennych}
plik:Text; {uchwyt pliku}
ok:boolean; {czy jest logged}
l:string; {tymczasowa zmienna}

begin
     clrscr; {czyscimy ekran}
     assign(plik,'dane.dtb'); {przypisujemy plik}
     reset(plik); {otwarcie do odczytu}
     readLN(plik,user); {wczytujemy - pierwsza linia to login}
     readLN(plik,passwd); {druga linia - haslo}
     repeat {start petli}
             clrscr; {czyscimy ekran w kazdym przebiegu petli}
             ok:=false; {niezalogowany}
             gotoXY(31,12); {mniej wiecej srodek ekranu}
             Write('Podaj login i halso:'); {wypisujemy prosbe o podanie loginu}
             GotoXY(28,13); {przesuwamy kursor}
             Write('Login: '); {login}
             GotoXY(36,13);
             readLN(us); {wczytujemy login}
             GotoXY(28,14);
             Write('Haslo: '); {haslo}
             GotoXY(36,14);
             readLN(ps); {wczytujemy haslo}
             clrscr; {czysciomy ekran}
             if us=user then begin {jezeli login sie zgadza...}
                if ps=passwd then begin {...i haslo jest dobre...}
                          clrscr;{....czyscimy ekran...}
                          ok:=true;{....zalogowani my...}
                           Write('Jestes zalogowany!');{witamy w systemie:)}
                           gotoxy(2,4);
                           repeat {petle odczytujaca wszystko z pliku}
                                 ReadLN(plik,l);
                                 writeLN(l);
                           until eof(plik); {until eof - przyklad na repeacie}
                end else begin {gdyby zle haslo}
             clrscr;
        write('Zle haslo');
        end;
     end else begin {gdy zly ogin}
     clrscr;
     write('Zly login');
     end;
     readln; {wstrzymujemy program}
     until ok=true; {powtarzamy do momentu kiedy sie zalogujemy}
     close(plik);{zamykamy plik}
     read(l);{wstrzymujemy program}
     end.{koniec ;)}

Fiuuu... poważny program:) Jak chcesz sobie poćwiczyć, to mam kilka propozycji na ćwiiczenia:
-System logowania dla kilku użytkowników (podpowiedź: zrób loginy i hasła w oddzielnym pliku)
-Przysłowia: niech program wybierze któreś z nich
-Przypominajka: Jeżeli upłynął termin, niech wyświetli komunikat.

Koniec z plikami tekstowymi. Teraz czas na rekordy. Mają one tę zaletę, że łatwo można w nich zapisać zawartość zmiennej. Zabawę rozpoczniemy od zrobienia sobie programu który przechowa dane jakiejś osoby:

program test3;
{(c) vXc SOFTWARE 2004 - Tomasz Banasiak
*** zajrzyj na www.vxcprogramming.prv.pl - strona o programowaniu
w PHP, Pascalu, Delphi i inne

 *** program ilustrujcy zapisywanie danych do pliku rekordowego
 na podstawie lekcji pana Marka Gabaly }

Uses CRT; {definiujemy uywane biblioteki}

type tdata = Record {definiujemy rekord z 2 stringami, i wiek - byte}
     imie:String;
     nazwisko:string;
     wiek:byte;
     end;

var
   data:Tdata; {nasz rekord}
   s:string; {zmienne potrzebne do wczytania}
   i:byte;
   plik:File of Tdata;

begin
   clrscr; {czycimy ekran}
   WriteLN('Podaj swoje imie: '); {prosimy uytkownika o wpisanie danych}
   readLN(s); {wczytujemy dane do zmiennej s}
   data.imie:=s;{przypisujemy dane do rekordu}
   WriteLN('Podaj nazwisko: ');
   ReadLN(s);
   data.nazwisko:=s;   {j/w, tylko przypisujemy do nazwiska}
   WriteLN('Wiek: [1..255 - wiecej chyba nie masz?]');    {:-)}
   ReadLN(i); {wczytamy dane byte}
   data.wiek:=i;
   { *** ZAPIS DO PLIKU}
   assign(plik,'dane_rekord.dtb');
   rewrite(plik);
   write(plik,data);
   close(plik);
end. {koniec programu}

Powyższy plik ma za zadanie tylko zapisać dane do pliku. Musieliśmy go utworzyć, bo inaczej nasz kolejny program by nie działał (Runtime Error blablabla). Od razu zrobimy wersje, która najpierw odczyta i wyświetli dane, a potem poprosi nas o ich zmiane:

{(c) vXc SOFTWARE 2004 - Tomasz Banasiak
*** zajrzyj na www.vxcprogramming.prv.pl - strona o programowaniu
w PHP, Pascalu, Delphi i inne

 *** program ilustrujcy zapisywanie danych do pliku rekordowego
 na podstawie lekcji pana Marka Gabaly }

Uses CRT; {definiujemy uywane biblioteki}

type tdata = Record {definiujemy rekord z 2 stringami, i wiek - byte}
     imie:String;
     nazwisko:string;
     wiek:byte;
     end;

var
   data:Tdata; {nasz rekord}
   s:string; {zmienne potrzebne do wczytania}
   i:byte;
   plik:File of Tdata;

begin
   clrscr; {czycimy ekran}
   { *** ODCZYT Z PLIKU}
   assign(plik,'dane_rekord.dtb');
   reset(plik);
   read(plik,data);
   close(plik);
   {koniec odczytu z pliku}
   writeLN('W pliku sa nastepujace dane:');
   writeLN('Imie: '+data.imie);
   writeLN('Nazwisko: '+data.nazwisko);
   writeLN('Wiek: ',data.wiek);
   writeLN('---============================================---');
   WriteLN('Podaj swoje imie: '); {prosimy uytkownika o wpisanie danych}
   readLN(s); {wczytujemy dane do zmiennej s}
   data.imie:=s;{przypisujemy dane do rekordu}
   WriteLN('Podaj nazwisko: ');
   ReadLN(s);
   data.nazwisko:=s;   {j/w, tylko przypisujemy do nazwiska}
   WriteLN('Wiek: [1..255 - wiecej chyba nie masz?]');    {:-)}
   ReadLN(i); {wczytamy dane byte}
   data.wiek:=i;
   { *** ZAPIS DO PLIKU}
   assign(plik,'dane_rekord.dtb');
   rewrite(plik);
   write(plik,data);
   close(plik);
end. {koniec programu}

Tak, to już coś. Prawie każdy rodzaj zmiennej można zapisywać w ten sposób. Aby utworzyć książke telefoniczną, musieliśmy dać w var
ksiazka:Array[0..100]of data;

i każdy wpis wczytywać a'la:

WriteLN(ksiazka[1].imie);

Więcej artykułów na www.vxcprogarmming.prv.pl

7 komentarzy

Dobry artykuł, nauczyłem się troche, a jak narazie jestem początkujący.

Lepsze to niż nic, wielce pomogło.

Artykuł oraz kod bardzo nieczytelny. Powinienes lepiej formatowac kod, a sam kod wziac pomiedzy znaczniki <code class="delphi"> i </code>.

eeehhh... art jest z mojej stronki, a ja mam oddzielnie <pascal> i &ltdelphi>... zaraz to poprawię...

Sam tego chciałeś, Bóg Cię skarcił

Jeśli już wziąłeś się za podstawy, to fajniebyłoby, gdybyś napisał również o plikach nietypowanych, których na dobrą sprawę w systemie zawsze jest najwięcej.