materiały
Transkrypt
materiały
Ćw 6: Operacje we/wy Lato 2013/2014 Ćwiczenie 6 – spis treści 1 2 3 Biblioteki wejścia/wyjścia w C Przykład użycia biblioteki we/wy niskiego poziomu Wczytywanie plików tekstowych Ćw 6: Operacje we/wy 2 / 28 Biblioteki wejścia/wyjścia w C Biblioteki wejścia/wyjścia w C 1 2 3 Biblioteki wejścia/wyjścia w C Przykład użycia biblioteki we/wy niskiego poziomu Wczytywanie plików tekstowych Ćw 6: Operacje we/wy 3 / 28 Biblioteki wejścia/wyjścia w C Biblioteki wejścia/wyjścia w C Nazwa biblioteki Biblioteka strumieni C Funkcje we/wy niskiego poziomu Funkcje we/wy systemu windows Plik nagłówkowy stdio.h Typ uchwytu do pliku FILE* io.h/– int windows.h HANDLE Ćw 6: Operacje we/wy 4 / 28 Biblioteki wejścia/wyjścia w C Analogiczne funkcje w różnych bibliotekach Operacja Otwieranie Odczyt Zapis Zamknięcie Kopiowanie uchwytu Standardowe wejście Standardowe wyjście Standardowe wyjście błędów fopen fread fwrite fclose Funkcje we/wy niskiego poziomu open/creat read write close fdopen dup/dup2 stdin 0 stdout 1 stderr 2 Biblioteka strumieni C Ćw 6: Operacje we/wy Funkcje we/wy Windows systemu CreateFile ReadFile WriteFile CloseHandle DuplicateHandle GetStdHandle (STD INPUT HANDLE) GetStdHandle (STD OUTPUT HANDLE) GetStdHandle (STD ERROR HANDLE) 5 / 28 Przykład użycia biblioteki we/wy niskiego poziomu Przykład użycia biblioteki we/wy niskiego poziomu 1 2 3 Biblioteki wejścia/wyjścia w C Przykład użycia biblioteki we/wy niskiego poziomu Wczytywanie plików tekstowych Ćw 6: Operacje we/wy 6 / 28 Przykład użycia biblioteki we/wy niskiego poziomu Przykład użycia biblioteki we/wy niskiego poziomu Przykład: Uruchamianie innego programu Mamy wykonywalną wersję programu (bez kodów źródłowych) wykonującego pewne obliczenia. Chcemy wywołać go w naszym programie, przekazując mu własne parametry. Ćw 6: Operacje we/wy 7 / 28 Przykład użycia biblioteki we/wy niskiego poziomu Uruchamianie innego programu int system(const char* command) – wykonuje komendę przekazaną w argumencie system i czeka na jej zakończenie. Zwraca -1 w przypadku błędu lub status wyjścia procesu w przypadku powodzenia. FILE*popen(const char*cmd,const char*type) – Uruchomienie komendy cmd. Jesli argument type jest tekstem "r", to ze zwróconego uchwytu można czytać wyjście komendy. Jeśli argument type jest tekstem "w", to do zwróconego uchwytu można pisać – dane bedą przekazywane na standardowe wejście komendy int pclose(FILE*fd) – Czeka na zakończenie działania komendy uruchomionej przez popen. Zwraca status zakończenia procesu lub -1 w przypadku błędu Ćw 6: Operacje we/wy 8 / 28 Przykład użycia biblioteki we/wy niskiego poziomu Funkcje systemowe do uruchamiania innego programu int fork(void) – tworzy kopię aktualnego procesu. W procesie oryginalnym zwraca identyfikator utworzonego procesu potomnego (kopii). W procesie potomnym zwraca wartość 0 int wait(int*pstatus) – czeka na zakończenie któregoś z procesów potomnych i odczytuje status jego zakończenia. Zwraca identyfikator procesu potomnego. int execv(const char*path,const char*args[]) – zaczyna wykonywac kod zapisany w pliku o ścieżce w path. Argument args jest przekazany do funkcji main w wykonywanym programie Ćw 6: Operacje we/wy 9 / 28 Przykład użycia biblioteki we/wy niskiego poziomu Uruchamianie innego programu if ( fork ()==0 ){ /* Proces potomy */ execv ( path , args ); } else { /* Proces oryginalny */ int status ; ... /* współpraca z procesem potomnym */ wait ( & status ); } Ćw 6: Operacje we/wy 10 / 28 Przykład użycia biblioteki we/wy niskiego poziomu Komunikacja między procesami int pipe(int fd[2]) – Tworzenie potoku. Do fd[0] zostanie wpisany deskryptor do odczytu, a do fd[1] – do pisania. Funkcja zwraca 0, gdy powiedzie się int dup(int fd) – kopiowanie deskryptora fd. Kopia deskryptora przyjmnie najmniejszą dostępną wartość i zostanie zwrócona int dup2(int old, int new) – kopiowanie deskryptora old. Kopia przyjmie wartość new. Jeśli ten deskryptor jest używany, zostanie wpierw zamknięty Ćw 6: Operacje we/wy 11 / 28 Przykład użycia biblioteki we/wy niskiego poziomu Przykład duplikowania deskryptorów plików int p_in [2] , p_out [2] , p_err [2]; pipe ( p_in ); pipe ( p_out ); pipe ( p_err ); if ( fork ()==0 ){ /* Proces potomy */ close ( p_in [1] ); dup2 ( p_in [0] , 0 ); close ( p_out [0] ); dup2 ( p_out [1] , 1 ); close ( p_err [0] ); dup2 ( p_err [1] , 2 ); execv ( path , args ); } else { /* Proces oryginalny */ close ( p_in [0] ); close ( p_out [1] ); close ( p_err [1] ); ... /* współpraca z procesem potomnym */ wait ( & status ); close ( p_in [1] ); close ( p_out [0] ); close ( p_err [0] ); } Ćw 6: Operacje we/wy 12 / 28 Wczytywanie plików tekstowych Wczytywanie plików tekstowych 1 2 3 Biblioteki wejścia/wyjścia w C Przykład użycia biblioteki we/wy niskiego poziomu Wczytywanie plików tekstowych Ćw 6: Operacje we/wy 13 / 28 Wczytywanie plików tekstowych Wczytywanie plików tekstowych Przykład: Mamy wczytać plik podzielony na linie. Każda linia zawiera 10 pól tekstowych oddzialonych separatorem „:”. Nie znamy dłogości linii (może być duża). Nie znamy ilości linii pliku. Ćw 6: Operacje we/wy 14 / 28 Wczytywanie plików tekstowych Interfejs Co będziemy zwracać: Nie znamy ilości linii więc lista lub dynamicznie alokowana tablica o zmiennym rozmiarze Ilość poznamy dopiero po wczytaniu, więc lista Co lista będzie zawierać: Zawsze 10 pól, więc tablica pól Definicja pola: Wskaźnik na dynamicznie zaalokowany łańcuch znaków Ćw 6: Operacje we/wy . 15 / 28 Wczytywanie plików tekstowych Interfejs Co będziemy zwracać: Nie znamy ilości linii więc lista lub dynamicznie alokowana tablica o zmiennym rozmiarze Ilość poznamy dopiero po wczytaniu, więc lista Co lista będzie zawierać: Zawsze 10 pól, więc tablica pól Definicja pola: Wskaźnik na dynamicznie zaalokowany łańcuch znaków Ćw 6: Operacje we/wy . 15 / 28 Wczytywanie plików tekstowych Interfejs Co będziemy zwracać: Nie znamy ilości linii więc lista lub dynamicznie alokowana tablica o zmiennym rozmiarze Ilość poznamy dopiero po wczytaniu, więc lista Co lista będzie zawierać: Zawsze 10 pól, więc tablica pól Definicja pola: Wskaźnik na dynamicznie zaalokowany łańcuch znaków Ćw 6: Operacje we/wy . 15 / 28 Wczytywanie plików tekstowych Interfejs Co będziemy zwracać: Nie znamy ilości linii więc lista lub dynamicznie alokowana tablica o zmiennym rozmiarze Ilość poznamy dopiero po wczytaniu, więc lista Co lista będzie zawierać: Zawsze 10 pól, więc tablica pól Definicja pola: Wskaźnik na dynamicznie zaalokowany łańcuch znaków Ćw 6: Operacje we/wy . 15 / 28 Wczytywanie plików tekstowych Interfejs Co będziemy zwracać: Nie znamy ilości linii więc lista lub dynamicznie alokowana tablica o zmiennym rozmiarze Ilość poznamy dopiero po wczytaniu, więc lista Co lista będzie zawierać: Zawsze 10 pól, więc tablica pól Definicja pola: Wskaźnik na dynamicznie zaalokowany łańcuch znaków Ćw 6: Operacje we/wy 15 / 28 Wczytywanie plików tekstowych Iterfejs II wczytaj plik.h 1 2 # ifndef _WCZYTAJ_PLIK_H # define _WCZYTAJ_PLIK_H 3 4 5 6 struct linia_pliku { char * pole [10]; }; 7 8 9 10 11 struct element_listy { struct linia_pliku dane ; struct element_listy * nast ; }; 12 13 14 15 struct element_listy * wczytaj_plik ( char * nazwa_pliku ); void zwolnij_liste ( struct element_listy * lista ); 16 17 # endif Ćw 6: Operacje we/wy 16 / 28 Wczytywanie plików tekstowych Implementacja Co wykona funkcja wczytaj plik: Otworzy plik W pętli wczyta dane (do znaku końca pliku) Zwróci wczytane wartości Ćw 6: Operacje we/wy . 17 / 28 Wczytywanie plików tekstowych Implementacja Co wykona funkcja wczytaj plik: Otworzy plik W pętli wczyta dane (do znaku końca pliku) Zwróci wczytane wartości Ćw 6: Operacje we/wy . 17 / 28 Wczytywanie plików tekstowych Implementacja Co wykona funkcja wczytaj plik: Otworzy plik W pętli wczyta dane (do znaku końca pliku) Zwróci wczytane wartości Ćw 6: Operacje we/wy 17 / 28 Wczytywanie plików tekstowych Implementacja II wczytaj plik.c 1 2 # include " wczytaj_plik . h " # include < stdio .h > 3 4 5 6 struct element_listy * wczytaj_plik ( char * nazwa_pliku ){ FILE * fd ; 7 8 9 10 11 /* Otwarcie pliku */ fd = fopen ( nazwa_pliku , " rt " ); if ( fd == NULL ) return NULL ; Ćw 6: Operacje we/wy 18 / 28 Wczytywanie plików tekstowych Obsługa błedów Niektóre deklaracje z pliku <errno.h>: extern int errno ; extern int sys_nerr ; const char * sys_errlist []; W pliku <string.h>: char * strerror ( int errnum ); W pliku <stdio.h>: void perror ( const char * s ); Ćw 6: Operacje we/wy 19 / 28 Wczytywanie plików tekstowych Implementacja III Wcztywanie linii przy pomocy: gets – Nie wiemy jak długa jest linia, więc ryzyko przepełnienia bufora fscanf("%s") – Podobnie jak poprzednio, dodatkowo w polach nie może wystąpić spacja fscanf("%[]") – Właściwe rozwiązanie scanf("%[a-z0-9]") – Wczytywanie tak długo póki występują znaki ’a’–’z’ lub ’0’-’9’ scanf("%[^:,]") – Wczytywanie tak długo póki nie występują znaki ’:’ lub ’,’ scanf("%50[^:\n]") – Wczytywanie do separatorów ’:’ lub nowej linii, jednak nie więcej niż 50 znaków Ćw 6: Operacje we/wy . 20 / 28 Wczytywanie plików tekstowych Implementacja III Wcztywanie linii przy pomocy: gets – Nie wiemy jak długa jest linia, więc ryzyko przepełnienia bufora fscanf("%s") – Podobnie jak poprzednio, dodatkowo w polach nie może wystąpić spacja fscanf("%[]") – Właściwe rozwiązanie scanf("%[a-z0-9]") – Wczytywanie tak długo póki występują znaki ’a’–’z’ lub ’0’-’9’ scanf("%[^:,]") – Wczytywanie tak długo póki nie występują znaki ’:’ lub ’,’ scanf("%50[^:\n]") – Wczytywanie do separatorów ’:’ lub nowej linii, jednak nie więcej niż 50 znaków Ćw 6: Operacje we/wy . 20 / 28 Wczytywanie plików tekstowych Implementacja III Wcztywanie linii przy pomocy: gets – Nie wiemy jak długa jest linia, więc ryzyko przepełnienia bufora fscanf("%s") – Podobnie jak poprzednio, dodatkowo w polach nie może wystąpić spacja fscanf("%[]") – Właściwe rozwiązanie scanf("%[a-z0-9]") – Wczytywanie tak długo póki występują znaki ’a’–’z’ lub ’0’-’9’ scanf("%[^:,]") – Wczytywanie tak długo póki nie występują znaki ’:’ lub ’,’ scanf("%50[^:\n]") – Wczytywanie do separatorów ’:’ lub nowej linii, jednak nie więcej niż 50 znaków Ćw 6: Operacje we/wy . 20 / 28 Wczytywanie plików tekstowych Implementacja III Wcztywanie linii przy pomocy: gets – Nie wiemy jak długa jest linia, więc ryzyko przepełnienia bufora fscanf("%s") – Podobnie jak poprzednio, dodatkowo w polach nie może wystąpić spacja fscanf("%[]") – Właściwe rozwiązanie scanf("%[a-z0-9]") – Wczytywanie tak długo póki występują znaki ’a’–’z’ lub ’0’-’9’ scanf("%[^:,]") – Wczytywanie tak długo póki nie występują znaki ’:’ lub ’,’ scanf("%50[^:\n]") – Wczytywanie do separatorów ’:’ lub nowej linii, jednak nie więcej niż 50 znaków Ćw 6: Operacje we/wy . 20 / 28 Wczytywanie plików tekstowych Implementacja III Wcztywanie linii przy pomocy: gets – Nie wiemy jak długa jest linia, więc ryzyko przepełnienia bufora fscanf("%s") – Podobnie jak poprzednio, dodatkowo w polach nie może wystąpić spacja fscanf("%[]") – Właściwe rozwiązanie scanf("%[a-z0-9]") – Wczytywanie tak długo póki występują znaki ’a’–’z’ lub ’0’-’9’ scanf("%[^:,]") – Wczytywanie tak długo póki nie występują znaki ’:’ lub ’,’ scanf("%50[^:\n]") – Wczytywanie do separatorów ’:’ lub nowej linii, jednak nie więcej niż 50 znaków Ćw 6: Operacje we/wy . 20 / 28 Wczytywanie plików tekstowych Implementacja III Wcztywanie linii przy pomocy: gets – Nie wiemy jak długa jest linia, więc ryzyko przepełnienia bufora fscanf("%s") – Podobnie jak poprzednio, dodatkowo w polach nie może wystąpić spacja fscanf("%[]") – Właściwe rozwiązanie scanf("%[a-z0-9]") – Wczytywanie tak długo póki występują znaki ’a’–’z’ lub ’0’-’9’ scanf("%[^:,]") – Wczytywanie tak długo póki nie występują znaki ’:’ lub ’,’ scanf("%50[^:\n]") – Wczytywanie do separatorów ’:’ lub nowej linii, jednak nie więcej niż 50 znaków Ćw 6: Operacje we/wy 20 / 28 Wczytywanie plików tekstowych Implementacja IV Możliwe dwa podejścia: Wczytujemy całą linię do pamięci, a potem dzielimy na pola (przy użyciu strchr) Wczytujemy poszczególne pola Możliwe sytuacje Wczytano tyle znaków, ile wynosi rozmiar bufora Wystąpił separator pola (tylko przy drugim rozwiązaniu) Wystąpił znak końca linii Wystąpił koniec pliku scanf(":") – wczytanie z bufora znaku ”:” (i ignorowanie go) scanf("%[:]") – wczytanie z bufora znaku ”:”. Istnieje możliwość sprawdzenia, czy udało się Ćw 6: Operacje we/wy . 21 / 28 Wczytywanie plików tekstowych Implementacja IV Możliwe dwa podejścia: Wczytujemy całą linię do pamięci, a potem dzielimy na pola (przy użyciu strchr) Wczytujemy poszczególne pola Możliwe sytuacje Wczytano tyle znaków, ile wynosi rozmiar bufora Wystąpił separator pola (tylko przy drugim rozwiązaniu) Wystąpił znak końca linii Wystąpił koniec pliku scanf(":") – wczytanie z bufora znaku ”:” (i ignorowanie go) scanf("%[:]") – wczytanie z bufora znaku ”:”. Istnieje możliwość sprawdzenia, czy udało się Ćw 6: Operacje we/wy . 21 / 28 Wczytywanie plików tekstowych Implementacja IV Możliwe dwa podejścia: Wczytujemy całą linię do pamięci, a potem dzielimy na pola (przy użyciu strchr) Wczytujemy poszczególne pola Możliwe sytuacje Wczytano tyle znaków, ile wynosi rozmiar bufora Wystąpił separator pola (tylko przy drugim rozwiązaniu) Wystąpił znak końca linii Wystąpił koniec pliku scanf(":") – wczytanie z bufora znaku ”:” (i ignorowanie go) scanf("%[:]") – wczytanie z bufora znaku ”:”. Istnieje możliwość sprawdzenia, czy udało się Ćw 6: Operacje we/wy . 21 / 28 Wczytywanie plików tekstowych Implementacja IV Możliwe dwa podejścia: Wczytujemy całą linię do pamięci, a potem dzielimy na pola (przy użyciu strchr) Wczytujemy poszczególne pola Możliwe sytuacje Wczytano tyle znaków, ile wynosi rozmiar bufora Wystąpił separator pola (tylko przy drugim rozwiązaniu) Wystąpił znak końca linii Wystąpił koniec pliku scanf(":") – wczytanie z bufora znaku ”:” (i ignorowanie go) scanf("%[:]") – wczytanie z bufora znaku ”:”. Istnieje możliwość sprawdzenia, czy udało się Ćw 6: Operacje we/wy 21 / 28 Wczytywanie plików tekstowych Implementacja V – Idea 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 while (1){ int st = fscanf ( fd , "%50[^\ n :]" , buff ); if ( st == 1 ){ /* Wczytano coś */ int len2 = strlen ( buff ); ... /* wczytano coś */ } else if ( fscanf ( fd , "%1[:]" , buff )==1 ){ ... /* wczytano separator pola */ } else if ( fscanf ( fd , "%1[\ n ]" , buff )==1){ ... /* wczytano koniec linii */ } else if ( feof ( fd ) ) { break ; /* Koniec pliku , wyjście */ } else assert (0); } Ćw 6: Operacje we/wy 22 / 28 Wczytywanie plików tekstowych Implementacja VI – Zwolnienie pamięci 1 2 3 # include < stdio .h > # include < stdlib .h > # include < assert .h > 4 5 6 7 8 9 10 11 12 13 14 15 void zwolnij_liste ( struct element_listy * lista ){ while ( lista != NULL ){ int idx ; struct element_listy * p2 = lista - > nast ; for ( idx =0; idx <10; idx ++) free ( lista - > dane . pole [ idx ] ); free ( lista ); lista = p2 ; } } Ćw 6: Operacje we/wy 23 / 28 Wczytywanie plików tekstowych Implementacja VII – Inicjalizacja 24 25 26 27 28 29 30 31 struct element_listy * wczytaj_plik ( char * nazwa_pliku ){ FILE * fd ; int idx = 0; int last_len = 0; struct linia_pliku line ; struct element_listy * res = NULL ; struct element_listy * last_rec = NULL ; 32 33 34 35 36 fd = fopen (" dane . txt " ," rt "); if ( fd == NULL ){ return NULL ; } 37 38 line . pole [ idx ] = malloc ( 1 ); Ćw 6: Operacje we/wy 24 / 28 Wczytywanie plików tekstowych Implementacja VIII – Obsługa odczytu treści pola 40 41 42 43 44 45 46 47 48 49 50 51 52 53 while (1){ char buff [51]; int st ; st = fscanf ( fd , "%50[^\ n :]" , buff ); if ( st == 1 ){ /* Wczytano coś */ int len2 , newlen ; len2 = strlen ( buff ); newlen = last_len + len2 ; line . pole [ idx ] = realloc ( line . pole [ idx ] , newlen +1 ); memcpy ( res + len , buff , len2 +1 ); continue ; } Ćw 6: Operacje we/wy 25 / 28 Wczytywanie plików tekstowych Implementacja IX – Obsługa odczytu separatora pola 54 55 56 57 58 59 60 61 62 63 else if ( fscanf ( fd ,"%1[:]" , buff )==1){ idx ++; if ( idx ==10){ ERROR_FREE return NULL ; } last_len = 0; line . pole [ idx ] = malloc ( 1 ); continue ; } Ćw 6: Operacje we/wy . 26 / 28 Wczytywanie plików tekstowych Implementacja IX – Obsługa odczytu separatora pola 17 18 19 20 21 22 54 55 56 57 58 59 60 61 62 63 # define ERROR_FREE \ while ( idx >=0 ){ \ free ( line . pole [ idx ] ); \ idx - -; \ } \ zwolnij_liste ( res ); else if ( fscanf ( fd ,"%1[:]" , buff )==1){ idx ++; if ( idx ==10){ ERROR_FREE return NULL ; } last_len = 0; line . pole [ idx ] = malloc ( 1 ); continue ; } Ćw 6: Operacje we/wy 26 / 28 Wczytywanie plików tekstowych Implementacja X – Obsługa odczytu końca linii 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 else if ( fscanf ( fd ,"%1[\ n ]" , buff )==1){ if ( idx !=9){ ERROR_FREE return NULL ; } if ( last_rec == NULL ){ assert ( res == NULL ); res = malloc ( sizeof ( struct element_listy ) ); last_rec = rec ; } else { last_rec - > nast = malloc ( sizeof ( struct element_listy ) ); last_rec = last_rec - > nast ; } last_rec - > dane = line ; last_rec - > nast = NULL ; idx = 0; last_len = 0; line . pole [ idx ] = malloc ( 1 ); continue ; } Ćw 6: Operacje we/wy 27 / 28 Wczytywanie plików tekstowych Implementacja XI – Obsługa odczytu końca pliku else if ( feof ( fd ) ) { if ( idx ==0 && last_len ==0 ){ free ( line . pole [0] ); fclose ( fd ); return res ; } ERROR_FREE return NULL ; } else assert (0); 86 87 88 89 90 91 92 93 94 95 96 } assert (0); return NULL ; 97 98 99 100 } Ćw 6: Operacje we/wy 28 / 28