Programowanie Procedurale. Pliki w języku C++ Bożena Woźna-Szcześniak bwozna@gmail.com Jan Długosz University, Poland Wykład 10 Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w języku 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 przewinięcie 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 następnie odczytać (read) lub zapisać (write) dane, które nas interesuja. Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w języku 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ć operację 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 się z dwóch rzeczy: Jedna to jest biblioteka fstream (ifstream, ofstream i iostream). Druga to biblioteka odziedziczona z C, dostępna przez plik nagłówkowy <cstdio>. Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w języku 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 języku C++ Wykład 10 4 / 22
Dostęp do pliku Trzy kroki które musza zostać wykonane przy dostępie 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 języku 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 się do konkretnego pliku dyskowego. W obrębie struktury FILE można znaleźć: rozmiar pliku, znacznik pozycji w pliku, adres bufora danych itp. Wywołać funkcję 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 języku C++ Wykład 10 6 / 22
fopen (char const* path, char const* mode); path - nazwa pliku wraz z ewentualna ścieźka dostępu. Nazwa ta może zostać podana bezpośrednio lub przez zmienna przechowujac a tablicę znaków. Jeśli operacja otwarcia pliku nie powiedzie się, 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 języku 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 języku C++ Wykład 10 8 / 22
Dostęp 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 listę argumentów: fwrite(void * buffer, long size, long count, FILE * stream ); buffer - adres poczatku pamięci spod której kopiowane/zapisywane będa dane size - rozmiar pojedynczego bloku pamięci (elementu) count - ilość elementów do skopiowania stream - wskaźnik do strumienia pliku Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w języku 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 względem poczatku, aktualnej pozycji lub końca strumienia: fseek ( strumien, offset, seek_dir ) ; gdzie seek_dir może wynosić: SEEK_SET - położenie względem poczatku pliku SEEK_CURR - położenie względem aktualnego położenia SEEK_END - położenie względem 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 języku 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 języku 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 języku C++ Wykład 10 12 / 22
Obsługa plików tekstowych - zapis Do obsługi plików stosuje się funkcje analogiczne jak printf i scanf, z tym, że zawieraja one wskaźnik do strumienia, z którego dane będa odczytywane czy też zapisywane. Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w języku 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 języku 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 języku 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 języku C++ Wykład 10 16 / 22
Odczyt danych z pliku tekstowego Załóżmy że mamy następujacy 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 więc wzorzec: "%d,%f" Ten sam wzorzec stosuje się do odczytu przy wykorzystaniu funkcji fscanf(). int fscanf ( FILE * stream, const char * format,... ); Bożena Woźna-Szcześniak (AJD) Programowanie Procedurale. Pliki w języku 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 języku 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 języku 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 języku 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 języku 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 języku C++ Wykład 10 22 / 22