Obsługa plików - część I

Do tej pory dane dla naszych programów były wpisywane z klawiatury, a wyniki wypisywane na ekran. Dużo bardziej przydałaby się jednak metoda pamiętania informacji w jakiś trwalszy i łatwiejszy do przekazania programowi sposób. Taka metodą są pliki dyskowe. Pascal potrafi zapisywać i odczytywać zwykłe pliki w systemnie operacyjnym.

Podstawową sprawą w zrozumieniu obsługi plików jest pojęcie typu pliku. Oczywiście z punktu widzenia sysytemu operacujnego wszystkie pliki są podobne - są po prostu bajtami zapisanymi jeden po drugim. Z punktu widzenia programu są jednak zapisanymi danymi, i aby program wiedział, jaki jest rodzaj i struktura tych danych, określa się dla pliku jego typ.

Definicja zmiennej typu plikowego może mieć jedną z poniższych form:

Var

   PlikTekstowy : Text;
   PlikJakiegosTypu : file of TypElementow;
   PlikBezTypu : file;

Typ elementów pliku może być dowolny: liczbowy, wyliczeniowy, tablicowy, rekordowy.

Najprostszym typem plików są pliki tekstowe. Pamiętamy w nich tekst można wczytywać w podobny sposób, jak byłby wpisywany przez użytkownika na klawiaturze. Zapisywanie do takiego pliku nie różni się specjalnie od wypisywania tekstu na ekran.

Do plików o określonym typie elementów możemy zapisywać (i odczytywać z nich) tylko zmienne takiego właśnie typu. Żeby nie było niejasności: dowolny plik, istniejący na dysku można otworzyć i próbować czytać jako strukturę elementów dowolnego typu. Co najwyżej otrzymamy bzdury. Oczywiście sensownym wydaje się czytanie z pliku elementów tego samego typu, jakie się w nim zapisało (choć zdarzają się ustępstwa od tej zasady). Znaczy to, że do pliku o zadeklarowanym typie w programie nie można zapisać zmiennej innego typu.

Pliok bez określonego typu umożliwia odczytywanie i zapisywanie jego części "porcjami", zdefiniowanymi przez użytkownika. Jest to sprawa nieco bardziej złożona i zajmiemy się tym troche później.

Przed wykonaniem jakiejkolwiek operacji na pliku, musimy dokonac przypisania nazwy pliku zmiennej plikowej. Dokonuje się tego procedurą:

   Assign (ZmiennaPlikowa, Nazwa)

ZmiennaPlikowa musi być uprzednio zadeklarowaną zmienną typu plikowego, a Nazwa jest nazwą pliku w systemie (może być z pełną lub względną ścieżką). Poniżej podany jest przykład deklarowania zmiennej plikowej

Var

   Plik : Text;

begin
Assign(Plik, 'C:\Folder\test.txt');

Następnie należy plik otworzyć jednym z poleceń:

Reset (zmiennaPlikowa);
Rewrite (zmiennaPlikowa);

Procedury te mają różne znaczenie w zależności od tego, czy mamy do czynienia z plikeim typu Text, czy file of Typ. W przypadku pliku tekstowego Reset otwiera istnijący plik na dysku i pozwala wyłącznie na czytanie z niego. Rewrite tworzy plik nowy plik (a jeżeli plik o przypisanej nazwie był na dysku kasuje jego zawartość) i pozwala jedynie na zapisanie tekstu. Jeżeli mamy do czynienia z plikiem elementów określonego typu, Reset otwiera istniejący plik i pozwala zarówno na czytanie jak i na pisanie w naszym bieżącym położeniu w pliku (na początku znajdujemy się przed pierwszym elementem, po przeczytaniu lub zapisaniu dowolnego zawsze przesuwamy się o jedną pozycje do przodu). Rewrite zaś tworzy nowy plik lub kasuje juz istniejący, pozwalająć także na zapisywanie i czytanie elementów z bieżacego położenia w pliku.

Dla plików tekstowych istnieje jeszcze trzecia metoda otwarcia:

Append (zmiennaPlikowa);

Procedura ta otwiera plik tekstowy w trybie dopisywania na jego końcu.

Pojęcie bieżącego położenia w pliku jest niezwykle istotne. W przeciwieństwie do tablic, w których mieliśmy dostęp do dowolnej komórki, podając jej indeks, pliki są bardziej jak taśma magnetofonowa. W danym momencie mamy dostęp jedynie do bieżącego elementu (czyli następnego po tym, który przeczytaliśmy lub zapisaliśmy ostatnio). W przypadku plików tekstowych możemy jedynie przesuwać się "w przód " pliku, odczytując bądź zapisując kolejne elementy. W przypadku plików typu nie-tekstowego możemy dokonać co prawda "przewinięcia" do przodu bądź do tyłu, ale w dalszym ciągu nie ma możliwości podania po prostu, w którym miejscu należy coś zapisać lub odczytać (choć sami możemy napisać procedury, wykonujące takie operacje).

Po zakończeniu działania z plikiem należy go zamknąć poleceniem:

Close (zmiennaPlikowa);

Do dyspozycji mamy jeszcze bardzo przydatne funkcje i procedury. Dla plików tekstowych przeznaczona jest funkcja:

Eoln (zmiennaPlikowa) : Boolean;

Zwraca ona wartość True, jeżeli znajdziemy się na końcu wiersza i False w przeciwnym razie. Dla plików tekstowych i nietekstowych bardzo pomocna jest ta funkcja:

Eof (zmiennaPlikowa) : Boolean;

Przyjmuje wartość prawdziwą, jeżeli znajdujemy się na końcu pliku, a False - jeżeli nie.

Dla plików typu file of Typ do dyspozycji mamy funkcje:

FilePos (zmiennaPlikowa) : Longint;

która określa, na której pozycji w pliku się znajdujemy (czyli, ile elementów pliku jest już "za nami") oraz:

FileSize (zmiennaPlikowa) : Longint;

Oblicza ona rozmiar pliku (czyli ile elementów danego typu zawiera). Dostępna jest także procedura:

Seek (zmienna, Pozycja);

Przesuwa nas ona do określonego miejsca w pliku. Uzywając procedury Seek oraz funkcji FilePos, należy pamiętać, że elementy pliku są numerowane od 0. Aby więc ustawić się przed pierwszym elementem (a więc na początku pliku), należy użyć procedury: Seek(F,0). Aby udać się do ostaniego elementu pliku - Seek(F, FileSize(F)-1).FilePost(F)=1 oznacza, że kolejnym przeczytanym elementem będzie drugi element pliku.

W celu odczytania elementów z pliku używamy znanych nam już instrukcji:

Read (zmiennaPlikowa, Element);
ReadLn (zmiennaPlikowa, Element);

Pierwsza z nich ma zastosowanie dla dowolnego pliku. Czyta z niego pojedynczy element. Drugiej używa się jedynie w plikach tekstowych. Po przeczytaniu elementu instrukcja powoduje przejście do kolejnego wiersza tekstu. Bardzo podobnie odbywa się zapis do pliku. Do dyspozycji mamy instrukcje:

Write (zmiennaPlikowa, Element);
WriteLn (zmiennaPlikowa, Element);

Pierwsza powoduje zapisanie elementów w pliku dowolnego typu. Druga ma zastosowanie tylko dla plików tekstowych. Powoduje zapisanie elemnetu i przejście do nowego wiersza.

Poniżej napiszemy sobie przykład użycia kilku powyzszych funcji. Napiszemy program, który do pliku tekstowego o nazwie wprow.txt zapisze wprowadzony przez użytkownika tekst. Zapisywanie powinno zostać zakończone po napotkaniu pustego wiersza.
Czytanie tekstu wpisanego przez użytkownika będziemy wykonywać w pętli repeat .. until, aż do napotkania pustego wiersza

program plik1;

uses
       Crt;


const
       NazwaPliku = 'C:\wprow.txt';

var
       F : Text;
       wiersz : String;


begin
      Clrscr;
      Assign (F, NazwaPliku);
      Rewrite (F);
repeat
      readln (wiersz);
      if wiersz <> '' then
      writeln (F, wiersz);
until wiersz='';
      Close (F);

      writeLn ('Zapisywanie do pliku zakonczono.');
      readln;
end.

Napisz program, który wypisze na ekran tekst z utworzonego w poprzednim przykładzie pliku tekstowego o nazwie wprow.txt

Wykorzystaj konstrukcję bardzo często stosowaną dla przejrzenia całego pliku: while not Eof (Plik) do.

powrót