8 ŚRODOWISKO SYSTEMU UNIX _Z-----
Operacje wejścia i wyjścia są zwykle sekwencyjne: każde wywołanie funkcji read lub write odnosi się do miejsca w pliku tuż za pozycją osiągniętą przy poprzedniej operacji. Niekiedy zachodzi jednak potrzeba czytania z pliku lub pisania do pliku w dowolnej kolejności. Poruszanie się po pliku bez czytania czy pisania danych umożliwia odwołanie systemowe Iseek:
long lseek(int fd, long offset, int origin);
Funkcja Iseek zmienia bieżącą pozycje pliku o deskryptorze fd na pozycję wskazaną przez argument offset (odstęp), którą oblicza się względem punktu odniesienia określonego przez argument origin. Kolejne czytanie lub pisanie rozpocznie się od tej właśnie pozycji. Wartością origin może być 0, 1 lub 2 oznaczające odpowiednio, że odstęp ma być mierzony względem początku, bieżącej pozycji lub końca pliku. Aby na przykład dopisać dane do pliku, należy - przed pisaniem - poszukać jego końca:
lseek(fd, OL, 2);
(Tak reaguje interpretator poleceń w systemie Unix na przełączenie przepływu danych » oraz tak realizuje się tryb dostępu do pliku "a” w funkcji fopen.)
Wywołanie
lseek(fd, OL, 0);
powoduje powrót do początku pliku („przewinięcie** pliku - od ang. rewind).
Zwróć uwagę na argument OL; można to także zapisać (long)0 albo po prostu 0, jeśli funkcję Iseek zadeklarowano poprawnie.
Mając do dyspozycji funkcję Iseek, możemy traktować pliki mniej więcej tak, jak wielkie tablice (kosztem czasu dostępu). Na przykład, następująca funkcja czyta dowolną liczbę bajtów z dowolnego miejsca pliku. Funkcja ta zwraca liczbę przeczytanych bajtów lub -1 po wykryciu błędu.
#include ,,syscalls.h,,
/* get: przeczytaj n bajtów od pozycji pos */ int get(int fd, long pos, char *buf, int n)
{
if (lseek(fd, pos, 0) >= 0) /* ustaw pozycję */ return read(fd, buf, n); else
return -1;
}
8 5 PRZYKŁAD - REALIZACJA FUNKCJI FOPEN I GETC___—
-pows-r^ed—by
Wartością zwracaną przez Iseek jest liczba typu long dla nowej pożyj -1 w przypadku wystąpienia błędu. Funkcja fseek z biblioteki standar* dobna do Iseek z tym, że jej pierwszym argumentem jest wskaźnik pliku (FILE *) oraz że w przypadku błędu zwracana wartość jest różna od zera.
Przykład - realizacja funkcji fopen i getc
Aby zilustrować współpracę niektórych z opisanych odwołań systemowych, pokażemy realizację dwóch funkcji z biblioteki standardowej: fopen i getc.
Przypominamy, że w bibliotece standardowej pliki są identyfikowane za pomocą wskaźników plików, a nie za pomocą deskryptorów. Wskaźnik pliku jest wskaźnikiem do struktury zawierającej różne informacje o pliku: wskaźnik do bufora, dzięki któremu można czytać z pliku dużymi porcjami, licznik znaków pozostałych w buforze, wskaźnik do pozycji następnego znaku w buforze, deskryptor pliku oraz kilka znaczników, które opisują rodzaj dostępu do pliku (czytanie/pisanie), stan programu (wystąpienie błędów) itp.
Struktura danych opisujących plik jest zdefiniowana w standardowym nagłówku <stdio.h>. Nagłówek ten musi być włączany (za pomocą #include) do każdego pliku źródłowego, w którym używa się funkcji z biblioteki standardowej realizujących operacje wejścia-wyjścia. Jest on również włączony w funkcjach z tej biblioteki. W podanym dalej wyciągu z typowego pliku <stdio.h> te nazwy, które z założenia są przeznaczone do użytku tylko dla funkcji bibliotecznych, rozpoczynają się znakiem podkreślenia (przez co zmniejsza się prawdopodobieństwo kolizji z nazwami w programie użytkownika). Tę konwencję stosują wszystkie podprogramy z biblioteki standardowej.
#define OPEN_MAX 20 /* maks. liczba jednocześnie otwartych plików */ typedef struct _iobuf {
/* liczba znaków w buforze */
/* pozycja następnego znaku */ /* położenie bufora */
/* sposób dostępu do pliku */
/* deskryptor pliku */
int ent; char *ptr; char *base; int flag; int fd;
} FILE;
extern FILE _iob[OPEN_MAX];
233