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