Programowanie Procedurale. Pliki w jezyku C++
Transkrypt
Programowanie Procedurale. Pliki w jezyku C++
Programowanie Procedurale. Pliki w jezyku ˛ C++ Bożena Woźna-Szcześniak [email protected] Jan Długosz University, Poland Wykład 10 Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 1 / 22 Co to jest plik i do czego służy? Plik to dokument lub inny zbiór danych zapisany na dysku lub innym nośniku, oznaczony unikatowa˛ nazwa. ˛ Plik jest ciagiem ˛ bajtów i ma określony poczatek ˛ i koniec. Dane w pliku ułożone sa˛ jedna po drugiej. Odczyt pliku realizowany jest tak jak odczyt z kasety magnetofonowej (odtworzenie pewnego fragmentu powoduje przewiniecie ˛ kasety), a tym samym ponowne odtworzenie spowoduje przeczytanie/odtworzenie nowego fragmentu. Aby odczytać pewien fragment pliku nalezy najpierw ustawić wskaźnik aktualnego położenia na poczatek ˛ fragmentu, który chcemy przeczytać/zapisać a nastepnie ˛ odczytać (read) lub zapisać (write) dane, które nas interesuja. ˛ Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 2 / 22 Strumienie Strumienie (ang. stream) zapewniaja˛ przepływ danych z programu do pliku lub odwrotnie. Strumień nie jest zwiazany ˛ z konkretnym urzadzeniem. ˛ Aby przeprowadzić operacje˛ wejścia/wyjścia, należy skojarzyć plik ze strumieniem. Istnieja˛ dwa formaty strumieni: tekstowy oraz binarny Biblioteka standardowa C++ w kwestii operacji wejścia/wyjścia składa sie˛ z dwóch rzeczy: Jedna to jest biblioteka fstream (ifstream, ofstream i iostream). Druga to biblioteka odziedziczona z C, dostepna ˛ przez plik nagłówkowy <cstdio>. Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 3 / 22 Pliki tekstowe a pliki binarne Brak różnicy dla tekstu, ale istnieja˛ istotne różnice w formie przechowywania liczb. W plikach binarnych położenie kolejnej danej określane jest na podstawie rozmiaru poprzedniej. W plikach tekstowych dane rozdzielone sa˛ znakami, przecinkami, średnikami, spacjami, tabulatorami itp. Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 4 / 22 Dostep ˛ do pliku Trzy kroki które musza˛ zostać wykonane przy dostepie ˛ do pliku: 1. Otworzyć plik 2. Odczyt lub/i zapis 3. Zamknać ˛ plik Przy tradycyjnym sposobie obsługi plików krok 1 i 3 sa˛ takie same niezależnie od tego czy mamy do czynienia z plikiem tektowym czy binarnym. Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 5 / 22 Otwarcie pliku - fopen Zadeklarować wskaźnik do pliku typu FILE – handler Struktura FILE służy do zarzadzania ˛ plikami i jest zdefiniowana w pliku <cstdio>. Wskaźnik typu FILE służy do odwoływania sie˛ do konkretnego pliku dyskowego. W obrebie ˛ struktury FILE można znaleźć: rozmiar pliku, znacznik pozycji w pliku , adres bufora danych itp. Wywołać funkcje˛ fopen(). Funkcja ta przekazuje wskaźnik do otwartego strumienia pliku. Przykład: FILE * strumien = fopen ( "Plik.txt", "wt") ; Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 6 / 22 fopen (char const* path, char const* mode); path - nazwa pliku wraz z ewentualna˛ ścieźka˛ dostepu. ˛ Nazwa ta może zostać podana bezpośrednio lub przez zmienna˛ przechowujac ˛ a˛ tablice˛ znaków. Jeśli operacja otwarcia pliku nie powiedzie sie, ˛ to funkcja zwraca wskaźnik pusty (null pointer). mode - tryby otwarcia pliku: wt lub w- otwarcie pliku ASCII do zapisu (plik jest tworzony od nowa), rt lub r - otwarcie pliku ASCII do odczytu, at lub a- otwarcie pliku ASCII do dołaczenia ˛ (zapisu na końcu pliku) wb, rb, ab - jak wyżej tylko dla plików binarnych Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 7 / 22 fopen (char const* path, char const* mode); mode - tryby otwarcia pliku: r+t, r+b - otwarcie pliku do zapisu i odczytu (wskaźnik jest ustawiany na poczatku ˛ pliku). w+t, w+b - plik jest tworzony od nowa (jeśli istnieje to jest czyszczony i otwierany do odczytu i zapisu). a+t, a+b - tak samo jak dla r+ z tym, że wskaźnik ustawiany jest na końcu. Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 8 / 22 Dostep ˛ do pliku binarnego Zapis/odczyt realizowany jest za pomoca˛ funkcji fwrite, fread. Funkcje dokonuja˛ zapisu/odczytu wyspecyfikowanej ilości bajtów poczawszy ˛ od aktualnej pozycji w strumieniu. Funkcie fread i fwrite maja˛ taka˛ sama liste˛ argumentów: fwrite(void * buffer, long size, long count, FILE * stream ); buffer - adres poczatku ˛ pamieci ˛ spod której kopiowane/zapisywane bed ˛ a˛ dane size - rozmiar pojedynczego bloku pamieci ˛ (elementu) count - ilość elementów do skopiowania stream - wskaźnik do strumienia pliku Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 9 / 22 Przemieszczanie w pliku Aktualne położenie w pliku: FILE * strumien = fopen ("Plik.bin", "w+b"); int pos = ftell ( strumien ) ; Przesuniecie połozenia w strumieniu do pozycji wzgledem ˛ poczatku, ˛ aktualnej pozycji lub końca strumienia: fseek ( strumien , offset , seek_dir ) ; gdzie seek_dir może wynosić: SEEK_SET - położenie wzgledem ˛ poczatku ˛ pliku SEEK_CURR - położenie wzgledem ˛ aktualnego położenia SEEK_END - położenie wzgledem ˛ końca pliku Przykład: fseek ( strumien ,100 ,SEEK_SET ) ; Przykład: fseek ( strumien , 0L , SEEK_SET ); równoważne rewind(strumien); Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 10 / 22 Przykład #include <cstdio> #include <cstring> #include <iostream> using namespace std; int main() { FILE * strumien = fopen ("Plik.bin", "w+b"); if (strumien) { cout << "Udalo sie otworzyc plik " << endl;} else {cout << "Nie udalo sie otworzyc pliku "<< endl;} int zmienna1 = 5; long zmienna2 = 8; long zmienna3 = 0xCCCCCC; int tab []={10,16,8,1} ; char napis [] = "zwykly t e k s t"; fwrite (&zmienna1 , sizeof (int) ,1 , strumien ) ; fwrite (&zmienna2 , sizeof (long) ,1 , strumien ) ; fwrite (&zmienna3 , sizeof (long) ,1 , strumien ) ; fwrite (&tab , sizeof (int) ,4 , strumien ) ; fwrite (napis , sizeof (char) , strlen (napis) , strumien ) ; ... Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 11 / 22 Przykład ... rewind(strumien); int a; fread (&a, sizeof (int) ,1 , strumien ) ; long b, c; fread (&b , sizeof (long) ,1 , strumien ) ; fread (&c , sizeof (long) ,1 , strumien ) ; cout << a << " " << b << " " << hex << c << dec << endl; int *s = new int [4]; fread (s , sizeof (int) ,4 , strumien ) ; for (int i = 0; i< 4 ; i++) cout<< s[i] << " "; cout << endl; char *s2 = new char [strlen(napis)+1]; fread (s2 , sizeof (char) ,strlen(napis) , strumien ) ; for (int i = 0; i< strlen(napis) ; i++) cout<< s2[i] << " "; cout << endl; fclose (strumien) ; return 0; } Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 12 / 22 Obsługa plików tekstowych - zapis Do obsługi plików stosuje sie˛ funkcje analogiczne jak printf i scanf, z tym, że zawieraja˛ one wskaźnik do strumienia, z którego dane bed ˛ a˛ odczytywane czy też zapisywane. Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 13 / 22 Przykład #include <cstdio> #include <iostream> using namespace std; int main() { FILE * strumien = fopen ("Plik.txt", "w+t"); if (strumien) { cout << "Udalo sie otworzyc plik " << endl;} else {cout << "Nie udalo sie otworzyc pliku "<< endl;} int z1 = 5; long z2 = 8; long z3 = 0xCCCCCC; int tab []={10, 16, 8, 1} ; char napis [] = "zwykly t e k s t"; //printf ( "%d , %ld , %ld , %s ",z1,z2,z3,napis) ; cout << z1 << " " << z2 << " " << hex << z3 << dec << " " << napis << endl; fprintf (strumien,"%d , %ld , %ld , %s " ,z1,z2,z3,napis) ; fclose (strumien) ; return 0; } Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 14 / 22 Obsługa plików tekstowych - zapis Funkcje printf() i fprintf() umożliwiaja˛ ustawienie minimalnej szerokości pola oraz precyzji (ilości miejsc po przecinku) w wyświetlaniu liczb zmiennoprzecinkowych: float liczba =1.5673892; printf ( "%f ", liczba ) ; // wyświetla liczbe z domyślnymi ustawieniami printf("%f10.3 n ", liczba ); printf("%f10.4 n ", liczba ); // wyświetla liczbe na polu 10 znakowym z dokładnościa˛ do 3 miejsc po przecinku Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 15 / 22 Przykład #include <cstdio> #include <cstring> #include <iostream> using namespace std; int main () { FILE * pFile = fopen ("myfile.txt","w"); char name [100]; for (int n=0 ; n<3 ; n++) { cout << "please, enter a name: "; fgets (name,100,stdin); name[strlen(name)-1]=’\0’; fprintf (pFile, "Name %d [%-10.10s]\n",n,name); } fclose (pFile); return 0; } Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 16 / 22 Odczyt danych z pliku tekstowego Załóżmy że mamy nastepuj ˛ acy ˛ plik: 1,1.1 2,14.3 6,12.8 zawiera on w każdej linii dwie liczby: całkowita˛ oraz zmiennoprzecinkowa. ˛ Do wyświetlenia pojedynczej linii na ekranie służy wiec ˛ wzorzec: "%d,%f" Ten sam wzorzec stosuje sie˛ do odczytu przy wykorzystaniu funkcji fscanf(). int fscanf ( FILE * stream, const char * format, ... ); Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 17 / 22 Przykład #include <cstdio> int main () { char str [80]; float f; FILE * pFile = fopen ("myfile.txt","w+"); fprintf (pFile, "%f %s", 3.1416, "PI"); rewind (pFile); fscanf (pFile, "%f", &f); fscanf (pFile, "%s", str); fclose (pFile); printf ("I have read: %f and %s \n",f,str); return 0; } Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 18 / 22 Przykład #include <cstdio> int main() { int c; while ((c = getc(stdin)) != EOF) { putc(c, stdout); } return 0; } Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 19 / 22 Przykład #include <iostream> using namespace std; int main() { int c; c = cin.get(); while (!cin.eof()) { cout << (char)c; c = cin.get(); } return 0; } Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 20 / 22 Przykład #include <iostream> #include <cstdio> using namespace std; int main(int argc, char *argv[]) { int ch; FILE* fp; long long counter = 0; if (argc != 2) { cout <<"Sposób użycia: "<< argv[0] << "nazwaPliku\n"; return 1; } if ((fp = fopen(argv[1], "r")) == NULL) { cout<<"Nie można otworzyć pliku o nazwie "<<argv[1]<<endl; return 1; } while ((ch = getc(fp)) != EOF) ++counter; fclose(fp); cout << "Ilość znaków w pliku o nazwie: " << argv[1] <<" " << counter << endl; return 0; } Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 21 / 22 Przykład #include <iostream> #include <fstream> using namespace std; int main(int argc, char *argv[]) { char ch; fstream is; long long counter = 0; if (argc != 2) { cout <<"Sposób użycia: "<< argv[0] << "nazwaPliku\n"; return 1; } is.open (argv[1]); if (!is.is_open()) { cout<<"Nie można otworzyć pliku o nazwie: "<<argv[1]<< endl; return 1; } while (is.good()) { ch = is.get(); // get character from file if (is.good()) ++counter; } is.close(); cout<<"Ilość znaków w pliku: "<<argv[1]<<" = "<<counter<<endl; return 0; } Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w jezyku ˛ C++ Wykład 10 22 / 22