Programowanie strukturalne wykład pliki tekstowe Agata Półrola Wydział Matematyki UŁ sem. letni 2011/2012 http://www.math.uni.lodz.pl/~polrola
Pliki wewnętrzne i zewnętrzne Dotychczas przy pobieraniu danych korzystaliśmy ze standardowego wejścia (standard input; zazwyczaj była to klawiatura), a wyniki wyprowadzaliśmy na standardowe wyjście (standard output; zazwyczaj ekran)
Istnieje wiele innych źródeł danych wejściowych czy miejsc do wyprowadzenia danych wynikowych (np. dysk, drukarka...). Nazywa się je plikami zewnętrznymi (external files). Program czyta i zapisuje dane do plików wewnętrznych (internal files). Pliki wewnętrzne są logicznymi miejscami zapisu i pobierania danych
Przed rozpoczęciem odczytu/zapisu danych z plików wewnętrznych program musi skojarzyć je z plikami zewnętrznymi. Jest to nazywane otwarciem pliku wewnętrznego. Skojarzenie to może być różne w różnych wykonaniach programu. Niektóre kompilatory Ady pozwalają na skojarzenie wielu plików wewnętrznych z jednym zewnętrznym, w innych jest to niedozwolone.
Wejście i wyjście tekstowe Dotychczas korzystaliśmy z tekstowego wejścia i wyjścia. W ich przypadku pliki są traktowane jako ciągi znaków. Tekstowa operacja wejścia czyta ciąg następujących po sobie znaków, interpretuje je jako wartość pewnego typu i przekazuje tę wartość do programu Tekstowa operacja wyjścia zapisuje sekwencję znaków reprezentujących pewną wartość pewnego typu
Pliki tekstowe Pliki tekstowe są plikami o dostępie sekwencyjnym (sequential-access files) odczyt danych rozpoczyna się zawsze od początku pliku; zapis jest dokonywany na końcu pliku nie ma możliwości zapisu w dowolnym miejscu pliku i odczytu z dowolnego miejsca pliku
do obsługi plików tekstowych służą pakiety ada.text_io ada.wide_text_io w/w pakiety różnią się tylko typem danych są to odpowiednio sekwencje elementów typu character i wide_character
Typ plikowy i zdefiniowane tryby otwarcia plików Oba pakiety definiują typ plikowy File_Type i typ wyliczeniowy File_Mode zmienne typu file_type stanowią pliki wewnętrzne (służą do odwoływania się do plików zewnętrznych) typ file_mode określa możliwe tryby pracy z plikiem (tryby otwarcia pliku) dla plików o dostępie sekwencyjnym jest to: type File_Mode is (In_File, Out_File, Append_File)
Tryby otwarcia pliku Dane mogą być przekazywane z programu do pliku lub z pliku do programu. Dozwolone operacje zależą od trybu otwarcia pliku. Każdy otwarty plik ma pewien bieżący tryb. Niekiedy można go zmienić przez tzw. resetowanie pliku.
tryb in oznacza, że program może czytać dane z pliku (input file) tryb out oznacza, że program może zapisywać dane w pliku (output file) pliki o dostępie sekwencyjnym mogą być otwarte w trybie append (dopisywania), co oznacza, że program może zapisywać dane do istniejącego pliku, zachowując przy tym jego dotychczasową zawartość
Operacje na plikach zewnętrznych Oba pakiety zawierają podprogramy o tych samych nazwach i roli: tworzenie pliku: procedure Create (File: in out File_Type; Mode: in File_Mode := Out_File; Name: in String := ; Form: in String := ); Parametry Name i Form określają plik zewnętrzny: jego nazwę i pewne cechy związane z systemem
otwieranie pliku: procedure Open (File: in out File_Type; Mode: in File_Mode; Name: in String; Form: in String := ); Parametr Form może być użyty do określenia pewnych cech charakterystycznych pliku zależnych od systemu, np. czy może być współdzielony, czy system może ograniczyć prawa zapisu/odczytu względem tego pliku itp
obie procedury (Create, Open) powodują powiązanie zmiennej plikowej File z plikiem o nazwie podanej w parametrze Name. Od tego momentu odwołujemy się do pliku zewnętrznego używając zmiennej plikowej
Uwaga otwarcie istniejącego już pliku tekstowego w trybie out powoduje że dotychczasowa zawartość pliku znika, a plik zawiera tylko dane zapisane przy ostatnim otwarciu
zamykanie pliku: procedure Close (File: in out File_Type); procedure Delete (File: in out File_Type); Procedury Close i Delete zamykają plik likwidując przy tym powiązanie między plikiem wewnętrznym i zewnętrznym, Delete dodatkowo usuwa zewnętrzny plik jeśli jest to możliwe Ada nie definiuje co stanie się jeśli nie zamkniemy pliku przy kończeniu programu (nie zamyka ich automatycznie). Brak zamknięcia pliku może (ale nie musi) spowodować utratę zapisywanych do niego danych czy problemy z dostępem do pliku
resetowanie pliku: procedure Reset (File: in out File_Type; Mode: in File_Mode); procedure Reset (File: in out File_Type); Resetowanie odpowiada zamknięciu i ponownemu otwarciu pliku w tym samym trybie w którym był otwarty wcześniej (jeśli nie podano nowego trybu), lub otwarciu go w nowym trybie.
określenie stanu pliku: function Is_Open (File: File_Type) return Boolean; function Name (File: File_Type) return String; function Form (File: File_Type) return String; function Mode (File: File_Type) return File_Mode;
Wyjątki Status_Error próba skorzystania z pliku wewnętrznego który nie został otwarty lub otwarcia już otwartego pliku Mode_Error próba odczytu z pliku w trybie out lub append albo próba zapisu do pliku w trybie in Name_Error próba skojarzenia pliku wewnętrznego z plikiem zewnętrznym o niepoprawnej nazwie
Device_Error problem ze sprzętem, oprogramowaniem lub nośnikiem udostępniającym usługi wejścia/wyjścia Use_Error próba wykonania operacji wejścia/wyjścia na pliku dla którego jest to niedozwolone (np. ze względu na prawa dostępu w systemie operacyjnym) End_Error próba czytania danych za końcem pliku wejściowego
Data_Error dane wejściowe w formacie innym od oczekiwanego Layout_Error niepoprawne operacje formatowania w przypadku wyjścia tekstowego
wszystkie wymienione wyjątki zdefiniowane są w pakiecie Ada.IO_Exceptions, dołączanym (with) przez pakiet Ada.text_io
plik:file_type; nazwa: string(1..10); n:natural; begin... put( Podaj nazwe pliku: ); get_line(nazwa,n); begin Open(plik, out_file, nazwa(1..n)); exception when Name_Error => Create(plik, out_file, nazwa(1..n)); end;
Operacje wejścia/wyjścia dla plików tekstowych Plik tekstowy jest sekwencją stron (jednej lub więcej), zakończoną znakiem końca pliku. Każda strona jest sekwencją linii (jednej lub więcej), zakończoną znakiem końca strony Każda linia jest ciągiem znaków, zakończoną znakiem końca linii znaki końca zależą od implementacji
Można określić maksymalną długość linii i strony dla pliku wyjściowego (out) Znaki w linii, linie na stronie, strony w pliku są numerowane (zaczynając od 1) Pakiety zawierają typ całkowity Count o zakresie od 0 do pewnej maksymalnej wartości zależnej od implementacji. Numery znaków, linii, stron są typu Count. Pakiety definiują też podtyp Positive_Count typu Count (o zakresie od 1 do Count last).
Określenie bieżącej pozycji w pliku tekstowym: function Page (File: File_Type) return Positive_Count; function Line (File: File_Type) return Positive_Count; function Col (File: File_Type) return Positive_Count; Przykład: with ada.text_io, ada.integer_text_io; use ada.text_io, ada.integer_text_io; put( Biezaca linia: ); put( Integer(Line(plik)) );
Kontrolowanie struktury linii i stron w pliku wyjściowym (out): procedure Set_Line_Length (File: in File_Type; To: in Count); procedure Set_Page_Length (File: in File_Type; To: in Count); procedure New_Line (File: in File_Type; Spacing: in Positive_Count :=1 ); procedure New_Page (File: in File_Type); procedure Set_Col (File: in File_Type; To: in Count); procedure Set_Col (File: in File_Type; To: in Count);
Określenie bieżących ustawień maksymalnej długości linii / strony: function Line_Length (File: File_Type) return Count; function Page_Length (File: File_Type) return Count;
Kolumny, linie i strony w pliku wejściowym (in): procedure Skip_Line (File: in File_Type; Spacing: in Positive_Count:=1); procedure Skip_Page (File: in File_Type); Możemy korzystać z procedur Set_Line i Set_Col, ale ze względu na dostęp sekwencyjny można przesuwać się tylko w przód (tj. zwiększając numer linii / strony)
Sprawdzenie bieżącej pozycji w pliku: function End_of_Line (File: File_Type) return Boolean; function End_of_Page (File: File_Type) return Boolean; function End_of_File (File: File_Type) return Boolean;
Odczyt i zapis do pliku tekstowego procedure Get (File: in File_Type; Item: out Character); procedure Get (File: in File_Type; Item: out String); procedure Put (File: in File_Type; Item: in Character); procedure Put (File: in File_Type; Item: in String); procedure Get_Line (File: in File_Type; Item: out String; Last: out Natural); procedure Put_Line (File: in File_Type; Item: in String);
with ada.text_io; use ada.text_io; procedure odczyt_pliku is plik:file_type; nazwa: string(1..10); n:natural; linia:string(1..100); begin put("podaj nazwe pliku "); get_line(nazwa,n); open(plik,in_file,nazwa(1..n)); while not end_of_file(plik) loop get_line(plik,linia,n); put(linia(1..n));put_line("*"); end loop; end odczyt_pliku;
Pakiety ada.text_io i ada.wide_text_io posiadają pakiety potomne umożliwiające wprowadzanie i wyprowadzanie wartości należących do różnych typów skalarnych (np. typów całkowitych, zmienno- i stałoprzecinkowych) Można zatem odczytywać z plików tekstowych np. dane całkowite (integer), zmiennoprzecinkowe (float) itp. podobnie można odczytywać elementy typu wyliczeniowego
with ada.text_io, ada.integer_text_io; use ada.text_io, ada.integer_text_io; procedure pliki_int is plik:file_type; nazwa:string(1..10); suma:integer:=0; n:integer; begin put("podaj nazwe pliku "); get_line(nazwa,n); open(plik,in_file,nazwa(1..n)); while not end_of_file(plik) loop get(plik,n); put("odczytane: "); put(n); new_line; suma:=suma+n; end loop; put("suma liczb w pliku: "); put(suma); end pliki_int;
with ada.text_io; use ada.text_io; procedure pliki_dni is type dni_tyg is (pon, wt, sr, czw, pt, so, nie); package dni_io is new enumeration_io(dni_tyg); use dni_io; plik:file_type; nazwa:string(1..10); n:integer; d: dni_tyg; begin put("podaj nazwe pliku "); get_line(nazwa,n); open(plik,in_file,nazwa(1..n)); while not end_of_file(plik) loop get(plik,d); put("odczytane: "); put(d); new_line; end loop; end pliki_dni;