Obsługa plików w turbo pascalu
O plikach
Pliki przechowywane na dysku twardym mogą być formatu tekstowego lub binarnego. Gdy
otworzysz plik tekstowy, można przeczytać konkretną wiadomość. Gdy natomiast otworzysz
w edytorze tekstu plik binarny zobaczysz wiele nic nie mówiących Tobie znaków. Dla
komputera mają one jednak znaczenie.
W plikach przechowujemy dane, które chcemy zatrzymać po wyłączeniu programu. Mogą w
nich też znajdować się potrzebne informacje do działania naszego programu. Np. dane
personalne, mapy do gry, zdjęcia, muzyka, lista najlepszych wyników.
Pliki tekstowe
Obsługa plików typu tekstowego jest bardzo prosta. Prawie nie różni się od zwyczajnego
używania procedur Write, WriteLn, Read, ReadLn. Najpierw jednak potrzebujemy otworzyć
konkretny plik i zapamiętać jego uchwyt (miejsce przez które będziemy się z nim łączyli).
Potem używamy odpowiednich procedur (Read, Write). Na koniec zamykamy plik. I to
wszystko!
Otwieranie plików
Kojarzenie plików odbywa się przed ich otwarciem, za pomocą procedury Assign(var F:File;
FileName:string); Dzięki kojarzeniu przypisujemy pewnej zmiennej uchwyt, czyli miejsce w
pamięci, które będzie identyfikować nasz plik.
W przypadku, gdy pracujemy na pliku tekstowym, uchwyt zmiennej będzie typu TEXT. W
innych przypadkach może być FILE, albo FILE OF {…} nazwa jakiegoś rekordu własnego
typu.
Otwieranie do odczytu
Aby otworzyć plik do odczytu skorzystaj z procedury Reset(var F:FILE; [RecSize:Word]).
Zmienna pierwsza typu FILE jest właśnie uchwytem do pliku, druga oznacza rozmiar
odczytywanego rekordu, domyślnie 128.
Otwieranie do zapisu
Do zapisu pliku służy procedura Rewrite(var F:FILE; [RecSize:Word]). Jej parametry
skonstruowane podobnie jak Reset.
Przykłady użycia
{naglowek i potrzebne zmienne}
program zapis_i_odczyt;
var F:Text;
s:string;
begin
{najpierw zapis do pliku}
Assign(F, 'plik.txt');
Rewrite(F);
WriteLn(F, 'Ala ma kota');
Close(F);
{teraz odczyt z pliku}
Assign(F, 'plik.txt');
Reset(F);
ReadLn(F, s);
Close(F);
WriteLn(s);
end.
Z plików tekstowych można odczytywać również liczby. Jeśli ma być ich wiele, muszą być
oddzielone pojedynczymi spacjami. Wtedy podobnie jak wczytujemy z klawiatury, możemy
użyć wczytywania z plików,
np. odczytanie trzech liczb z pliku, którego zawartość to:
1 2 3
wykonujemy za pomocą
ReadLn(F, a, b, c);
Gdy w następnej lini jest kilka innych liczb, niekoniecznie tyle samo, można wczytać je w
kolejnej instrukcji ReadLn. Jednak programista musi czuwać nad tym, by nie wowołać
pustego wczytywania, czyli takiego gdy plik się już skończył.
Uwaga!
Nie jest dobrze traktować plików binarnych (np. bitmapy) jako tekstowych i odczytywać ich
zawartość po jednym znaku typu char (ani kopiować plików w ten sposób). Oczywiście
całość zadziała i można wyświetlić taki rysunek lub skopiować plik, jednak wczytywanie z
pliku bajt po bajcie (również zapisywanie) jest bardzo czasochłonne. Zwykła bitmapa może
być wczytywana nawet kilka sekund! Za pomocą instrukcji BlockRead i BlockWrite można
to zrobić w granicach kilkunastu milisekund.
Pliki binarne
Wczytywanie i zapisywanie w plikach binarnych odbywa się za pomocą instrukcji
BlockRead, BlockWrite. Jest to bardzo szybka metoda zapisu i odczytu. Najlepiej zobaczyć
prosty przykład w pomocy pascala, który kopiuje plik podany jako parametr programu na
miejsce podane drugim parametrem
{Blockrd.PAS}
{Sample code for the BlockRead and BlockWrite procedures.}
program CopyFile;
{ Simple, fast file copy program with NO error-checking }
{ For Windows: }
{ uses WinCrt; }
var
FromF, ToF: file; {uchwyty do plikow}
NumRead, NumWritten: Word;
Buf: array[1..2048] of Char; {bufor, do ktorego beda trafialy wczytane dane z pliku
pierwszego}
begin
Assign(FromF, ParamStr(1)); { Otwiera plik podany przez pierwszy parametr }
Reset(FromF, 1);
Assign(ToF, ParamStr(2)); { Przygotowuje do zapisu drugi plik }
Rewrite(ToF, 1); { Record size = 1 }
Writeln('Copying ', FileSize(FromF), ' bytes...');
repeat
BlockRead(FromF, Buf, SizeOf(Buf), NumRead); {odczytywanie bloku o rozmiarze 2KB
(NumRead teraz okresla rozmiar)}
BlockWrite(ToF, Buf, NumRead, NumWritten); {zapisywanie odczytanego bloku}
until (NumRead = 0) or (NumWritten <> NumRead); {kopiowanie do momentu skopiowania
calego pliku lub gdy wystapi blad}
Close(FromF); {Zamykanie plikow}
Close(ToF);
end.
Ten program nie zadziała tak od razu. Trzeba podać mu 2 parametry, które będą oznaczały 2
pliki. Pierwszym musi być plik, który rzeczywiście istnieje na dysku. Drugi parametr to plik
tworzony. Jak wpisać te parametry? W menu Turbo Pascala wybierz Run->Parameters I
wpisz np. C:plik.txt C:Kopia.txt.
Teraz utwórz na dysku C: plik o nazwie plik.txt i wpisz do niego jakąś zawartość. Gdy
uruchomisz program, zobaczysz, że na dysku powstał drugi plik o nazwie Kopia.txt, w
dodatku z taką samą zawartością jak plik.txt.
Warto zwrócić uwagę na pewną funkcję w podanym przykładzie. Chodzi o FileSize. Funkcja
FileSize zwraca rozmiar pliku, którego kojarzymy ze zmienną typu File.
Obsługa błędów
Podczas pracy z plikami, może się zdarzyć, że kopiowany plik nie istnieje albo że plik, do
którego chcemy coś dopisać został zabezpieczony, lub używa go inny program. Co wtedy?
Gdy nie dodamy zabezpieczeń, nasz program zostanie przerwany.
Pascal udostępnia dyrektywy kompilatora, które pozwalają na przejęcie kontroli nad
pojawiającymi się błędami. Taką dyrektywą jest {$I-} oraz {$I+} Gdy pomiędzy nimi
umieścimy kod, będzie on odporny na błędy wejścia/wyjścia, inaczej mówiąc odporny
również na błędy dotyczące obsługi plików.
A jak sprawdzić czy plik istnieje? Można napisać własną funkcję, np. FileExists. Będzie
próbowała otworzyć plik. Jeśli się nie uda, będzie zwracała wartość False, czyli plik nie
istnieje.
function FileExists(const FileName : string) : Boolean;
var F : File;
begin
{$I-}
Assign(F, FileName);
Reset(F, 1);
Close(F);
{$I+}
FileExists := IOResult = 0 ;
end;