Podstawy programowania II Wykład 3: Obsługa plików w stdio.h Plik Plik, zwany też zbiorem danych - skończony ciąg bajtów zapisany na nośniku danych, opatrzony nazwą. System plików - sposób organizacji plików zapisanych na nośnikach danych, który stanowi logiczną całość. Zazwyczaj posiada strukturę hierarchiczną poprzez katalogi. Katalog (folder) - opatrzony nazwą fragment nośnika danych lub innego katalogu, przeznaczony do umieszczania w nim plików i innych podkatalogów. Podkatalog - katalog utworzony wewnątrz innego katalogu Nazwa pliku lub katalogu to ciąg znaków identyfikujący jednoznacznie ten plik lub katalog. Nazwy nie mogą się powtarzać w ramach jednego katalogu. Ścieżka dostępu - rodzaj adresu katalogu w systemie plików. Składa się z ciągu nazw wszystkich katalogów od poziomu najwyższego do najniższego. Może rozpoczynać się od identyfikatora urządzenia (nośnika danych, np. dysku) Podstawy programowania II - Obsługa plików w stdio.h Rodzaje plików Z punktu widzenia programisty pliki dzielą się na: tekstowe - złożone ze znaków pogrupowanych w linie tekstu, zakończonych znakiem NEWLINE. NEWLINE może w różnych systemach mieć postać znaków '\13' i '\10' lub tylko '\10' binarne - złożone z dowolnych wartości binarnych, których struktura może być dowolna. W zależności od systemu mogą wystąpić różnice w kodowaniu: - kodowanie Little Endian - bajty od najmłodszego do najstarszego - kodowanie Big Endian - od najstarszego do najmłodszego, np.liczba 1000 (hex: 03e8) może być zapisana jako 03, e8 (big endian) lub 08, 03 (little endian) Po przeniesieniu na niewłaściwy system: 59395 (hex: e803) Podstawy programowania II - Obsługa plików w stdio.h Zastosowania plików w programie Dane wejściowe Dane wyjściowe Ustawienia programu Rejestracja zdarzeń (log, debug) Kopie danych Pomocnicze, tymczasowe Wygenerowane skrypty/programy Pliki są jedyną formą zapamiętania danych po zakończeniu pracy programu Podstawy programowania II - Obsługa plików w stdio.h Podstawowe operacje na plikach Utworzenie Otwarcie Zamknięcie Odczyt Zapis Podstawy programowania II - Obsługa plików w stdio.h Wskaźnik pozycji w pliku System operacyjny pamięta pozycję w pliku, której dotyczy następna operacja - odpowiednik kursora na ekranie Po otwarciu wskaźnik zawsze wskazuje pierwszy element pliku Każdy odczyt lub zapis powoduje przesunięcie wskaźnika o tyle bajtów ile zostało odczytane lub zapisane Możliwe jest sztuczne przesunięcie wskaźnika Można odczytać jego położenie W chwili zamknięcia pliku, jest on ucinany w punkcie wskazywanym przez wskaźnik pozycji Podstawy programowania II - Obsługa plików w stdio.h Koniec pliku (End-Of-File) Stan Eof osiągany jest jeżeli został odczytany ostatni bajt pliku lub nastąpiła próba odczytu większej liczby bajtów niż zostało do końca pliku. W bibliotece stdio.h zdefiniowana jest stała EOF, której wartość zwracana jest przez wiele funkcji m.in. w przypadku niepowodzenia polegającego na napotkaniu końca pliku. Do sprawdzania czy plik osiągnął stan Eof służy funkcja feof Podstawy programowania II - Obsługa plików w stdio.h Sytuacje błędne Istnieje szereg sytuacji, w których wykonanie operacji na pliku może się nie powieść. Może to rzutować na efekty kolejnych działań na tym pliku. Typowe sytuacje błędne plik lub katalog o podanej nazwie nie istnieje brak dostępu do pliku lub katalogu brak miejsca na dysku błąd zapisu błąd odczytu koniec pliku Należy po wykonaniu każdej operacji sprawdzać jej powodzenie w celu odpowiedniej reakcji na sytuacje błędne i uniknięcia błędów w wyniku kolejnej operacji. Podstawy programowania II - Obsługa plików w stdio.h Funkcje plikowe w <stdio.h> fopen - otwarcie/utworzenie fclose - zamknięcie fgetc, fgets, fscanf - odczyt (tekst) fread - odczyt (binarny) fputc, fputs, fprintf - zapis (tekst) fwrite - zapis (binarny) fseek - ustawienie wskaźnika ftell - odczyt pozycji wskaźnika feof - sprawdzenie stanu EOF Podstawy programowania II - Obsługa plików w stdio.h Struktura FILE struct FILE unsigned unsigned int int unsigned unsigned wchar_t char unsigned }; { char char *curp; *buffer; level; bsize; short istemp; short flags; hold; fd; char token; /* /* /* /* /* /* /* /* /* Current active pointer Data transfer buffer fill/empty level of buffer Buffer size Temporary file indicator File status flags Ungetc char if no buffer File descriptor Used for validity checking */ */ */ */ */ */ */ */ */ Tworzona dla każdego otwartego strumienia (w tym również pliku), opisuje jego stan. Większość funkcji wymaga podania wskaźnika na nią jako identyfikacji pliku Podstawy programowania II - Obsługa plików w stdio.h Otwarcie pliku (1) Prototyp: FILE * fopen(char * path, char *mode); Parametry: path - nazwa otwieranego pliku wraz ze ścieżką dostępu mode - określa cel otwarcia (odczyt, zapis itp.) String złożony ze znaków: 'r' - odczyt lub 'w' - zapis lub 'r+' - odczyt i ew. zapis lub 'w+'- zapis i ew. odczyt, 't' zapis tekstowy (domyślnie) lub 'b' - - zapis binarny Działanie: Otwiera plik o nazwie path w trybie określonym przez mode. Jeżeli mode to 'w', z pliku nie będzie można czytać Jeżeli mode to 'r', do pliku nie będzie można zapisywać Jeżeli mode zawiera 'w', plik jest tworzony na nowo jako pusty, a jeżeli wcześniej istniał, jest niszczony. Dla modyfikacji istniejącego pliku, należy użyć trybu 'r+'. Podstawy programowania II - Obsługa plików w stdio.h Otwarcie pliku (2) Zwracana wartość: Wskaźnik do struktury FILE, który jest potrzebny do pozostałych operacji na pliku. Jeżeli odczyt się nie powiedzie, zwracana jest wartość NULL (0). W takim przypadku nie wolno wykonywać żadnych operacji na pliku. Sprawdzenie wartości zwracanej przez fopen jest absolutną koniecznością. Podstawy programowania II - Obsługa plików w stdio.h Zamknięcie pliku Prototyp: int fclose(FILE *file); Parametry: file - wskaźnik na strukturę FILE otwartego pliku Działanie: Zamyka plik identyfikowany przez file. Bez ponownego otwarcia nie będzie można już dokonywać na nim żadnych operacji. Każdy plik, który został otwarty musi zostać zamknięty przed zakończeniem programu. Zaniechanie może powodować błędy w systemie plików (tzw. lost clusters), a efekt zapisu może zostać utracony. Zwracana wartość: 0 w przypadku powodzenia, EOF przy jego braku. Podstawy programowania II - Obsługa plików w stdio.h Otwarcie istniejącego pliku - przykład #include <stdio.h> void main() { FILE * plik; plik= fopen ("plik.txt", "rt"); // otwarcie if (plik!=NULL) // kontrola poprawności 'fopen' { //... tutaj dokonujemy odczytu z pliku fclose(plik); // zamknięcie! } else puts("Błędna nazwa pliku!");// reakcja na błąd } // tu nie zamykamy Podstawy programowania II - Obsługa plików w stdio.h Utworzenie pliku - przykład #include <stdio.h> void main() { char nazwa[200]; puts("Podaj nazwę pliku:"); gets(nazwa); FILE *plik= fopen (nazwa, "wt"); // utworzenie if (plik!=NULL) // kontrola poprawności 'fopen' { //... tutaj dokonujemy zapisu do pliku fclose(plik); // zamknięcie! } else puts("Błędna nazwa pliku!");// reakcja na błąd } Podstawy programowania II - Obsługa plików w stdio.h Zapis do pliku Funkcje dla fputc fputs fprintf trybu tekstowego: - zapis pojedynczego znaku (bajtu) - zapis ciągu znaków (stringu) - zapis sformatowanego tekstu Funkcja dla trybu binarnego: fwrite - zapis ciągu bajtów Jeżeli plik jest otwarty w trybie tekstowym, przy zapisie znaku '\n' zostanie on rozwinięty w sekwencję oznaczającą koniec linii właściwą dla danego systemu (np. '\13', '\10' na PC) Jeżeli plik jest otwarty w trybie binarnym, '\n' zostanie zapisany jako '\10' niezależnie od systemu. Podstawy programowania II - Obsługa plików w stdio.h Funkcja fputc Prototyp: int fputc(int znak, FILE *plik); Parametry: znak kod ASCII znaku, który ma być wysłany, plik wskaźnik do struktury FILE identyfikującej otwarty plik. Działanie: Zapis znaku do znak pliku identyfikowanego przez plik. Zwracana wartość W przypadku powodzenia, funkcja zwraca wartość znak. W przypadku błędu zwracana jest wartość EOF Podstawy programowania II - Obsługa plików w stdio.h Funkcja fputs Prototyp: int fputs (char *tekst, FILE *plik); Parametry: tekst wskaźnik do stringu zakończonego znakiem '\0'. plik wskaźnik do struktury FILE identyfikującej otwarty plik. Działanie: Zapis stringu tekst do pliku identyfikowanego przez plik. Na końcu nie jest zapisywany ani znak '\0' ani '\n'. Zwracana wartość W przypadku powodzenia zwracana jest wartość nieujemna. W przypadku błędu zwracana jest wartość EOF. Podstawy programowania II - Obsługa plików w stdio.h Funkcja fprintf Prototyp: int fprintf (FILE *plik, char *format, argumenty); Parametry: plik wskaźnik do struktury FILE identyfikującej otwarty plik. format string formatu, definiujący treść i format wyświetlanego tekstu, w którym można umieścić m.in. pola argumenty ciąg wyrażeń oddzielonych przecinkami, odpowiadających poszczególnym polom w formacie. Działanie Zapis do pliku identyfikowaengo przez plik, sformatowanego tekstu (identycznie jak dla funkcji printf) Zwracana wartość Funkcja zwraca całkowitą liczbę zapisanych znaków. W przypadku błędu zwracana jest wartość EOF. Podstawy programowania II - Obsługa plików w stdio.h Funkcja fwrite Prototyp: unsigned fwrite(void *ptr, unsigned rozmiar, unsigned n, FILE *plik); Parametry: ptr wskaźnik do początku zapisywanego obszaru, rozmiar rozmiar zapisywanego elementu, n liczba elementów (ułożonych po sobie w pamięci) do zapisania, plik wskaźnik do struktury FILE identyfikującej otwarty plik. Działanie Zapis do pliku identyfikowaengo przez plik, ciągu n *rozmiar bajtów pamięci począwszy od adresu wskazywanego przez ptr. Zwracana wartość Funkcja zwraca liczbę prawidłowo zapisanych elementów (nie bajtów!). Podstawy programowania II - Obsługa plików w stdio.h Odczyt z pliku Funkcje dla fgetc fgets fscanf trybu tekstowego: - odczyt pojedynczego znaku (bajtu) - odczyt ciągu znaków (stringu) - odczyt sformatowanego tekstu Funkcja dla trybu binarnego: fread - odczyt ciągu bajtów Jeżeli plik jest otwarty w trybie tekstowym, przy odczycie znaku '\n' zostanie on rozwinięty w sekwencję oznaczającą koniec linii właściwą dla danego systemu (np. '\13', '\10' na PC) Jeżeli plik jest otwarty w trybie binarnym, '\n' zostanie zapisany jako '\10' niezależnie od systemu. Podstawy programowania II - Obsługa plików w stdio.h Funkcja fgetc Prototyp: int fgetc (FILE *plik); Parametry: plik wskaźnik do struktury FILE identyfikującej otwarty plik. Działanie Odczyt pojedynczego znaku z pliku identyfikowanego przez plik. Zwracana wartość W przypadku powodzenia, funkcja zwraca kod odczytanego znaku jako typ int. W przypadku błędu lub napotkania końca pliku zwracana jest wartość EOF. Podstawy programowania II - Obsługa plików w stdio.h Funkcja fgets Prototyp: char *fgets (char *buf, int n, FILE *plik); Parametry: buf wskaźnik do fragmentu pamięci przeznaczonego na tekst. n maksymalna liczba znaków do odczytu zwiększona o 1. plik wskaźnik do struktury FILE identyfikującej otwarty plik Wczytuje ciąg znaków z pliku identyfikowanego przez plik, pod adres wskazywany przez buf, przy czym odczyt kończy się po napotkaniu znaku '\n' lub po wczytaniu n-1 znaków. Na końcu dodawany jest znak '\0'. Zwracana wartość: W przypadku powodzenia zwracany jest wskaźnik równy buf. W przypadku błędu lub napotkaniu końca pliku, zwracana jest wartość NULL. Podstawy programowania II - Obsługa plików w stdio.h Funkcja fscanf (1) Prototyp: int fscanf (FILE *plik, char *format, lista_wskaźników); Parametry: plik wskaźnik do struktury FILE identyfikującej otwarty plik format string definiujący oczekiwany format tekstu, w tym liczbę i rodzaj pól (wprowadzanych danych), lista_wskaźników ciąg wyrażeń o typie wskaźnikowym, oddzielonych przecinkami, odpowiadających poszczególnym polom w formacie. Działanie: Odczyt sformatowanych danych pod adresy wskazywane przez listę wskaźników z pliku identyfikowanego przez plik. Format i wskaźniki zdefiniowane są na zasadach identycznych jak dla funkcji scanf. Podstawy programowania II - Obsługa plików w stdio.h Funkcja fscanf (2) Zwracana wartość Funkcja zwraca liczbę prawidłowo odczytanych, przekonwertowanych i zapisanych pól. W przypadku błędu uniemożliwiającego odczyt, lub napotkania końca pliku, zwraca EOF. W miejsce funkcji fscanf często korzysta się z sekwencji: fgets (odczyt linii tekstu z pliku do stringu) i sscanf (odczyt sformatowanych danych ze stringu) Podstawy programowania II - Obsługa plików w stdio.h Funkcja fread Prototyp: unsigned fread(void *ptr, unsigned rozmiar, unsigned n, FILE *plik); Parametry: ptr wskaźnik, pod którym dane mają zostać zapisane w pamięci, rozmiar rozmiar odczytywanego elementu, n liczba elementów do odczytu, plik wskaźnik do struktury FILE identyfikującej otwarty plik. Działanie Odczyt z pliku identyfikowaengo przez plik, ciągu n *rozmiar bajtów do pamięci począwszy od adresu wskazywanego przez ptr. Zwracana wartość Funkcja zwraca liczbę prawidłowo odczytanych elementów (nie bajtów!). Podstawy programowania II - Obsługa plików w stdio.h Sprawdzanie stanu Eof Wielkość pliku nie jest znana podczas odczytu, więc w każdej chwili możemy osiągnąć jego koniec. Funkcje odczytujące zwracają tę samą wartość zarówno w przypadku błędu jak i napotkania końca pliku, co wymaga różnych reakcji programu Jeżeli wczytano dokładnie cały plik, odczyt powiedzie się, ale plik i tak przejdzie w stan Eof, co uniemożliwia dalszy odczyt. Do sprawdzenia czy taka sytuacja wystąpiła, służy funkcja: int feof (FILE *plik); Parametry: plik wskaźnik do struktury FILE identyfikującej otwarty plik Zwraca nie-zero jeżeli plik jest w stanie Eof, zero w przeciwnym wypadku Podstawy programowania II - Obsługa plików w stdio.h Zmiana wskaźnika pozycji pliku (1) Prototyp funkcji: int fseek(FILE *plik, long offset, int skąd); Parametry: plik wskaźnik do struktury FILE identyfikującej otwarty plik offset liczba bajtów, o którą wskaźnik ma być przesunięty skąd wartość określająca skąd należy liczyć pozycję, stałe: SEEK_SET (0) - początek pliku, SEEK_CUR (1) - aktualna pozycja SEEK_END (2) - koniec pliku Podstawy programowania II - Obsługa plików w stdio.h Zmiana wskaźnika pozycji pliku (2) Działanie: Przesunięcie wskaźnika pozycji w pliku o offset bajtów licząc od pozycji zdefiniowanej przez parametr skąd. offset może być wartością ujemną (zwłaszcza dla skąd==SEEK_END) Stan Eof jest resetowany jeżeli wystąpił wcześniej. Zwracana wartość: zero w przypadku powodzenia, nie-zero w przypadku błędu. Może się jednak zdarzyć, że wskaźnik nie zostanie przesunięty, a błąd nie zostanie wykryty, jeżeli system operacyjny nie umożliwia sprawdzenia wyniku (tak dzieje się w DOS'ie). Podstawy programowania II - Obsługa plików w stdio.h Powrót na początek pliku Prototyp funkcji: void rewind(FILE *plik); Parametry: plik wskaźnik do struktury FILE identyfikującej otwarty plik Działanie: Przesunięcie wskaźnika pozycji w pliku na początek. Stan Eof jest resetowany jeżeli wystąpił wcześniej Podstawy programowania II - Obsługa plików w stdio.h Odczytanie wskaźnika pozycji Prototyp funkcji: long ftell(FILE *plik); Parametry: plik wskaźnik do struktury FILE identyfikującej otwarty plik Działanie: Odczyt położenia wskaźnika pozycji w pliku. Zwracana wartość: W przypadku powodzenia: położenie wskaźnika pozycji w pliku licząc w bajtach od początku pliku (pierwszy bajt pliku to pozycja 0!) W przypadku błędu: -1 Podstawy programowania II - Obsługa plików w stdio.h Dziękuję fclose(prezentacja);