Język ANSI C Operacje we/wy Wykład: Programowanie komputerów Prowadzący: dr inż. Sławomir Nowak
Wprowadzenie Operacje wejścia wyjścia dotyczą zarówno typowych operacji na plikach (np. na dysku) jak też operacji elementarnych, jak np. wyświetlanie na ekranie i pobieranie danych z klawiatury. Opisane podejście dotyczy podejścia tzw. proceduralnego, za pomocą strumieni (zgodnie ze standardem Ansi C).
Wprowadzenie Aby korzystać z omawianych mechanizmów należy w nagłówku programu dołączyć plik stdio.h, zawiera on potrzebne funkcje do operacji wejścia-wyjścia. STRUMIENIE są to „zbiory”, z których pobierane są i do których wprowadzane są dane. Jeśli pobieramy dane z klawiatury za pomocą scanf lub wyprowadzamy za pomocą printf (lub innych funkcji), to nie musimy nic wiedzieć o strumieniach, bo w tych funkcjach strumieni są one standartowo „ustawione” na klawiaturę i ekran.
Strumienie standartowe Standartowo zdefiniowane strumienie to: stdin – wejściowy – klawiatura; stdout – wyjściowy – ekran; stderr – komunikatów o błędach – ekran stdprn – strumień drukarnki.
Strumienie standartowe Strumienie mają swoją reprezentację „programistyczną”. Są reprezentowane przez zmienne typu FILE (ściślej – przez wskaźnik na FILE). Czyli FILE jest nowym typem, co oznacza, że możemy deklarować odpowiednie zmienne tego typu (ściślej – wskaźniki).
Deklarowanie strumieni Jeśli chcemy w programie realizować operacje wejścia-wyjścia inne niż standardowe, na przykład na plikach na dysku, musimy zadeklarować wskaźnik do nowego, określonego przez nas strumienia, np.: FILE *strmj
Czynności przy operacjach wejścia-wyjścia Typowa sekwencja operacji wejścia-wyjścia, realizowana za pomocą strumienia polega na: 1. zadeklarowaniu wskaźnika do zmiennej strumieniowej; 2. otwarciu strumienia; 3. operacje na strumieniu (np. zapis i odczyt); 4. zamknięcie strumienia (należy o tym pamiętać, bo inaczej nasze dane mogą „zniknąć”).
Aby z niej skorzystać należy: Otwarcie strumienia Do otwierania strumienia wykorzystuje się funkcję fopen, która zwraca wskaźnik na strumień. Aby z niej skorzystać należy: - mieć zadeklarowany odpowiedni wskaźnik na strumień, - zdecydować się na określony tryb otwarcia pliku (na przykład „tylko do odczytu” - podać nazwę pliku. Logiczne, prawda?
Otwarcie strumienia Przykładowe otwarcie pliku: if (!(strm = fopen(”c:\\teksty\\tekst.txt”,”wb”))) puts (”Blad otwarcia pliku”); Jako parametry podano dwa łańcuchy znakowe: Pierwszy to nazwa pliku Uwaga!: W łańcuchach tekstowych znak ‘\’ oznaczamy jako ‘\\” aby odróżnić go od tzw. znaku specjalnego. Dlatego jest ”c:\\...” a nie ”c:\...” - Drugi oznacza tryb otwarcia pliku. Opisują do dwa znaki. Wskazane jest wykonywanie operacji otwarcia pliku razem z instrukcją if, tak jak na podanym przykładzie. Jeśli otwarcie pliku nie powiodło się, funkcja fopen zwraca wartość NULL, na którą możemy odpowiednio zareagować, na przykład poprzez odpowiedni komunikat.
Otwarcie strumienia - tryby Pierwszy znak oznacza sposób i cel otwarcia: w -> tylko do zapisu; r -> tylko do odczytu; a -> do zapisu na końcu istniejącego już pliku (jak APPEND z Pascal’a) r+ -> otwórz istniejący zbiór do zapisu i odczytu jednocześnie; w+ -> utwórz nowy plik do zapisu i odczytu (stary, jeśli istnieje, zostanie zastąpiony) a+ -> do zapisu i odczytu wskazanego zbioru, lub otworzy nowy plik jeśli nie istnieje. Drugi znak oznacza: b -> tryb binarny t-> tryb tekstowy.
Operacje na strumieniach Do operacji na strumieniu służą różne funkcje. Są one na ogół odpowiednikiem funkcji znanych wcześniej, do wyświetlania na ekranie i odczytu z klawiatury, tylko z dodaną literą f. Ich działanie jest analogiczne z tym, że dane wysyłane są i pobierane z pliku, a nie na ekran i klawiaturę.
Operacje na strumieniach - funkcje int fputc (int c, strm); wysyła do strumienia strm znak c. W przypadku błędu zwraca EOF (o tym później); int fputs (char *s, strm); wysyła do strumienia strm łańcuch tekstowy s. Oznaczenie char *s oznacza łańcuch tekstowy wskazywany przez zmienną s. Błąd zwraca EOF.
Operacje na strumieniach - funkcje int fprintf (strm, ”........”, ....); działa tak jak funkcja printf, tylko łańcuch znakowy zostanie wyprowadzony do strumienia strm. Zwraca EOF jeśli błąd. char* fgets(char *s, strm); działa jak gets, tylko, że odczytuje łańcuch tekstowy ze strumienia strm; int fgetc(strm); działa jak getc, tylko, że odczytuje znak ze strumienia strm; int scanf(strm, ”.....”,...); działa jak scanf, tylko, że odczytuje dane z łańcucha strm;
Operacje na strumieniach - funkcje korzystając z tych funkcji i odwołując się do strumieni standartowych, np. można zrealizować wypisanie łańcucha tekstowego na ekran: #include <stdio.h> int main(void) { char msg[] = "Hello world"; int i = 0; while (msg[i]) fputc(msg[i], stdout); i++; } return 0;
Funkcje feof Do operacji na plikach bardzo przydatna jest funkcja feof(strm) która określa, czy osiągnięty został koniec pliku. Dobrze jest wykorzystać ją razem z instrukcją while podczas odczytu z pliku, kiedy po każdym odczycie sprawdzamy, czy osiągnięty jest koniec pliku. Jeśli podczas ostatniej operacji na strumieniu osiągnięto koniec zbioru (pliku), wtedy zwraca ona wartość 1.
int fclose (nazwa_strumienia); Zamykanie strumieni Zamykanie strumieni jest bardzo proste. Realizowane jest za pomocą funkcji int fclose (nazwa_strumienia); Zamykanie strumienia jest ważne w związku z buforowaniem danych. Można skorzystać z funkcji fcloseall() która automatycznie zamyka wszystkie otwarte strumienia.
Przykłady prostych operacji na plikach Wykorzystanie eof() Otwierany jest plik jako strumień stream (do odczytu), jeśli po odczytaniu z niego jednego znaku osiągnięto koniec pliku, wyświetlany jest komunikat. int main(void){ FILE *stream; stream = fopen("DUMMY.FIL", "r"); fgetc(stream); /*odczytujemy znak, nigdzie go nie zapisujemy */ if (feof(stream)) printf("Osiagnieto koniec pliku\n"); fclose(stream); return 0; }
Przykłady prostych operacji na plikach Program tworzy kopię AUTOEXEC.BAT. Otwiera dwa strumienie, do odczytu in oraz do zapisu out (oba w trybie tekstowym). Następnie w pętli while przepisuje plik znak po znaku. Na końcu zamyka strumienie. int main(void){ FILE *in, *out; if ((in = fopen("\\AUTOEXEC.BAT", "rt"))== NULL) { fprintf(stderr, "Nie można otworzyc pliku.\n"); return 1; } if ((out = fopen("\\AUTOEXEC.BAK", "wt")) == NULL) { fprintf(stderr, "Nie mozna otworzyc pliku.\n"); while (!feof(in)) fputc(fgetc(in), out); fclose(in);fclose(out);return 0;
Przykłady prostych operacji na plikach Prosty przykład wykorzystanie funkcji fscanf do odpowiedniego reagowania na błędy wprowadzania wartości. Wprowadzamy liczbę typu int. Strumień jest określony jako stdin, czyli klawiatura. Komunikat o ewentualnym błędzie wprowadzania jest kierowany do strumienia stderr. #include <stdio.h> int main(void){ int i; printf("Wprowadz liczbe int: "); if (fscanf(stdin, "%d", &i)) printf("The integer read was: %i\n", i); else { fprintf(stderr, "Blad przy wprowadzaniu.\n"); exit(1); } return 0;
Podsumowanie
FILE * strm = fopen(”c:\\teksty\\tekst.txt”,”wb”) NULL -> 0