Slajd 1 z 13 C++ - [3-5] Pliki i strumienie w C++ Nysa 2004-2013. Autor: Wojciech Galiński. wersja dnia 19 maja 2013 r.
Slajd 2 z 13 Klasy i obiekty do obsługi plików Aby korzystać z obiektów do obsługi plików, należy dołączyć nagłówek fstream : #include <fstream> Do obsługi plików uzywamy obiektów następujących klas: ostream klasa służąca do zapisu danych do pliku; istream klasa służąca do odczyt danych z pliku; fstream klasa łącząca funkcjonalność powyższych klas. PRZYKŁADY: #include <fstream> using namespace std; int main() { ofstream oplik; ifstream iplik; fstream plik; } return 0; // wysyłanie danych do pliku // odczytywanie danych z pliku // czytanie i pisanie w pliku
Slajd 3 z 13 Otwieranie i zamykanie plików OTWIERANIE PLIKU odbywa się za pomocą funkcji składowej: nazwa_obiektu.open(nazwa_pliku, tryb) Parametr nazwa_pliku jest wartością typu C-string określającą ścieżkę dostępu do pliku. Parametr tryb jest trybem otwarcia pliku, np. do zapisu, do odczytu, do dopisywania. Wartości tego parametru opisane są w następnym slajdzie. ZAMYKANIE PLIKU odbywa się za pomocą funkcji składowej: nazwa_obiektu.close() PRZYKŁAD: ofstream plik; plik.open("plik.tmp"); plik << "Tekst" << endl; plik.close();
Slajd 4 z 13 Tryby otwierania i zamykania plików Oto najważniejsze wartości parametru tryb : ios::in otwarcie pliku do czytania (stdio: "r"); ios::out otwarcie pliku do pisania (stdio: "w"); ios::ate otwórz i ustaw na końcu zawartości (stdio: "a"); Poniższe trybów stosujemy tylko w połączeniu z powyższymi trybami: ios::trunc otwórz i skasuj starą treść (jeśli istnieje); ios::binary otwórz w trybie binarnym (domyślnie jest to tryb tekstowy). W trybie binarnym znak końca wiersza jest interpretowany jako zwykła wartość liczbowa. Najczęściej stosujemy połączenia powyższych trybów: ios::out ios::ate (stdio: "a"); ios::out ios::trunc (takie samo działanie, jak w przypadku ios::out); ios::in ios::out (stdio: "r+"); ios::in ios::out ios::trunc (stdio: "w+"). PRZYKŁADY: ifstream plik1; plik1.open("plik.tmp"); // operacje na pliku plik1.close(); fstream plik2; plik2.open("plik.tmp", ios::in ios::binary); // operacje na pliku plik2.close(); ofstream plik3; plik3.open("plik.tmp"); // operacje na pliku plik3.close(); fstream plik4; plik4.open("plik.tmp", ios::ate); // operacje na pliku plik4.close();
Slajd 5 z 13 Zapisywanie i odczytywanie danych tekstowych ODCZYT I ZAPIS PLIKÓW W TRYBIE TEKSTOWYM realizowany jest za pomocą operatorów przesunięcia danych: operator >> odczyt danych z pliku; operator << zapis danych do pliku. PRZYKŁAD ZAPISU: ofstream plik1("nazwa.txt"); string tekst1 = "test"; int liczba1 = 365; plik1 << tekst1 << '\n' << liczba1; plik1.close(); PRZYKŁAD ODCZYTU: ifstream plik2("nazwa.txt"); string tekst2; int liczba2; plik2 >> tekst2 >> liczba2; plik2.close(); cout << tekst2 << ' ' << liczba2 << endl;
Slajd 6 z 13 Błędy podczas obsługi plików FLAGI STANU BŁĘDU STRUMIENIA to wartości informujące o statusie (o błędach lub nie) pracy strumienia. Tak przechowywane są w komputerze flagi (bity) stanu (obok jest przedstawiona także definicja typu iostate : Funkcje składowe sprawdzające powyższe flagi: bool good() sprawdza, czy wszystkie flagi są wyłączone; bool eof() sprawdza, czy ustawiona jest flaga eofbit (osiągnięto koniec pliku); bool fail() sprawdza, czy ustawione są flagi failbit lub badbit (tekst zamiast liczby albo strumień został uszkodzony); bool bad() sprawdza, czy ustawiona jest flaga badbit (strumień został uszkodzony). Inne funkcje składowe związane z flagami stanu błędu strumienia: badbit failbit eofbit 4 2 1 rdstate() zwraca stan wszystkich flag jako słowo typu iostate ; clear() kasuje wszystkie flagi; setstate() ustawia pojedynczą flagę bez modyfikacji pozostałych flag. enum iostate { goodbit=0, eofbit=1, failbit=2, badbit=4 } PRZYKŁAD: int k = -5; double d = 2.72; string s = "tekst"; ofstream oplik("plik.txt"); if (oplik.good()) oplik << k << ' ' << d << endl << s << endl; oplik.close(); int k2; string s2; ifstream iplik("plik.tmp"); if (iplik.good()) { iplik >> k2 >> d >> s2; cout << k2 << endl << d << endl << s2 << endl; } else if (iplik.fail()) cout << "Błąd odczytu pliku"; iplik.close();
Slajd 7 z 13 Obsługa plików za pomocą fstream lista zadań ZADANIE 3.5.1: Utwórz w pliku tabliczkę mnożenia od 1 do 20 w formacie, który umożliwia import do arkusza kalkulacyjnego (np. CSV). ZADANIE 3.5.2: Utwórz w pliku wartości funkcji: f(x) = sin(x), x [-360, 360 ]. ZADANIE 3.5.3: Utwórz w pliku wartości funkcji: f(x) = ax 2 +bx+c, a, b, c [-10, 10] przechowywane w osobnym pliku, którego zawartość mozna wylosować osobną opcją. ZADANIE 3.5.4: Utwórz w pliku wartości funkcji podanej przez nauczyciela. ZADANIE 3.5.5: Zapisz w pliku daty imienin wybranych imion (min. 20) i wykonaj program, który sprawdza, kiedy są imieniny danego imienia oraz jakie imiona mają imieniny w danym dniu. Po dopisaniu do pliku nowych imion, mają być one uwzględniane w wyszukiwaniach. ZADANIE 3.5.6: Napisz program dodający nowe imiona do pliku z poprzedniego zadania. Pytaj o imię i datę imienin. Informuj o tym, czy dane imie jest już na liście. Korzystając z iostream utwórz pliki z następującą zawartością, a następnie odczytaj je i wyświetl na ekranie: ZADANIE 3.5.7: Potęgi kolejnych liczb całkowitych (jak najwięcej liczb z dokładnością do wszystkich cyfr). ZADANIE 3.5.8: Nazwiska wczytywane z klawiatury do momentu wpisania pustego tekstu. ZADANIE 3.5.9: Przedstaw dziesiętnie kolejne ułamki zwykłe o podstawach od 2 do N: 1/2 = 0.5, 1/3 = 0.333333, 2/3 = 0.666667, 1/4 = 0.25, 2/4 = 0.5, 3/4 = 0.75, 1/5 = 0.2, 2/5 = 0.4, 3/5 = 0.6, 4/5 = 0.8, 1/6 = 0.166667, 2/6 = 0.333333, 3/6 = 0.5,, (N-1)/N. Każdy ułamek w osobnym wierszu. ZADANIE 3.5.10: Zmodyfikuj wyniki poprzedniego zadania tak, aby takie same wartości dziesiętne były umieszczone w jednym wierszu, np. 1/2 = 2/4 = 3/6 = 0.5.
Slajd 8 z 13 Strumienie zapisujące do obiektu tekstowego STRINGSTREAM to klasa wywodząca się od klas zapisujących strumienie: przychodzący do obiektu klasy string (istringstream), oraz wychodzący z obiektu klasy string (ostringstream). Klasa stringstream i jej przodkowie wymagają dołączenia nagłówka sstream : #include <sstream> Najważniejsze z praktycznych zastosowań tej klasy to: zapisywanie strumieni przeznaczonych dla obiektu cout do obiektu klasy string ; PRZYKŁAD: ostringstream oss; string s; oss << "Ala ma " << (2*5*5) << " lat.\n"; cout << s << endl << oss.str() << endl; s = oss.str(); zapisywanie do obiektu liczbowego liczby przechowywanej jako tekst. int liczba; string tekst; cout << "Podaj liczbę: "; cin >> tekst; istringstream iss(tekst); iss >> liczba; cout << liczba << endl; ĆWICZENIE 3.5.1: Przeanalizuj powyższy kod. Opisz, jak działają powyższe konwersje.
Slajd 9 z 13 Klasy obsługujące strumienie Grupy klas (według rodzaju obsługiwanych obiektów): "istream", "ostream" i "iostream" klasy do obsługi ekranu i klawiatury "ifstream", "ofstream" i "fstream" klasy do obsługi plików "istringstream", "ostringstream" i "stringstream" klasy do obsługi obiektów klasy "string"
lajd 10 z 13 Zapisywanie i odczytywanie danych binarnych ODCZYT I ZAPIS PLIKÓW W TRYBIE BINARNYM realizowany jest odpowiednio za pomocą funkcji: read(char*, int) odczyt danych binarnych z pliku; write(char*, int) zapis danych binarnych do pliku. Pierwszy parametr to wskaźnik do danych w postaci kodów ASCII, a drugi parametr to liczba bajtów do przesłania. PRZYKŁAD ZAPISU: ofstream oplik("nazwa.txt"); int liczba = 35; oplik.write((char*)(&liczba), sizeof(liczba)); oplik.close(); PRZYKŁAD ODCZYTU: ifstream iplik("nazwa.txt"); int* wliczba; char bufor_[4], *bufor = bufor_; iplik.read(bufor, sizeof(liczba)); wliczba = (int*)(bufor); cout << *wliczba << endl; iplik.close();
lajd 11 z 13 Pozycjonowanie wskaźnika w pliku WSKAŹNIK W PLIKU to element wskazujący na miejsce, w którym będziemy zapisywać lub odczytywać dane (odpowiednik kursora dla pliku otwartego w edytorze tekstu). POZYCJONOWANIE WSKAŹNIKA W PLIKU to ustawianie wskaźnika pliku w wybranym przez nas miejscu. Stosuje się je przede wszystkim w przypadku plików binarnych. Funkcje składowe służące do pozycjonowania wskaźnika w pliku: enum seek_dir { beg, cur, end } pos_type tellg() odczytuje pozycję wskaźnika odczytu z pliku; pos_type tellp() odczytuje pozycję wskaźnika zapisu do pliku; pos_type seekg(long bajt, seek_dir punkt_odniesienia) ustawia pozycję wskaźnika odczytu z pliku; pos_type seekp(long bajt, seek_dir punkt_odniesienia) ustawia pozycję wskaźnika odczytu z pliku; Funkcje seekg i seekp ustawiają wskaźnik na odpowiedni bajt pliku względem początku (ios:beg) albo końca pliku (ios:end) albo względem bieżącego miejsca (ios:cur) Wskaźnik można ustawiać poza końcem pliku i można w to miejsce coś zapisywać, ale nie można z takiego miejsca nic odczytywać. PRZYKŁAD: int k[6] = {2, -4, 6, -8, 10, -12}; ofstream oplik("plik.tmp", ios::binary); for (int i=0; i<6; ++i) { char *bufor = (char*)(k+i); oplik.write(bufor, sizeof(int)); } oplik.close(); char temp_[4], *temp = temp_; ifstream iplik("plik.tmp", ios::binary); cout << "Pozycja wskaźnika w pliku: " << iplik.tellg() << endl; iplik.seekg(4, ios_base::beg); for (int i=0; i< 2; ++i) { iplik.seekg(4, ios_base::cur); cout << "Pozycja wskaźnika w pliku: " << iplik.tellg()<<"\n"; iplik.read(temp, sizeof(int)); int *liczba = (int*)(temp); cout << "Wartość z tablicy: " << *liczba << endl; } cout << "Pozycja wskaźnika w pliku: " << iplik.tellg() << endl; iplik.close();
lajd 12 z 13 Obsługa strumieni w sstream lista zadań ZADANIE 3.5.11: Zapytaj współrzędne końców odcinka i oblicz jego długość. Odpowiedź przedstaw tak jak w następującym przykładzie: Długość odcinka wynosi 5 cm.. ZADANIE 3.5.12: Wczytuj liczby całkowite za pomocą funkcji getline i zapisz je do zmiennej typu long long albo long double (wybierz najbardziej pasujący typ). ZADANIE 3.5.13: Zapytaj o bok i jeden z kątów ostrów trójkąta prostokątnego, a następnie oblicz długości pozostałych boków korzystając z funkcji trygonometrycznych. Odpowiedzi podawaj pełnym zdaniem, np. Przyprostokątna przyległa ma długość 12 cm.. ZADANIE 3.5.14: Wczytaj tekst funkcją getline, znajdź tam tam liczby i dopisz je odpowiednio do tablicy liczb całkowitych albo do tablicy liczb zmiennoprzecinkowych. ZADANIE 3.5.15: Utwórz bazę danych Ksiażka telefoniczna zawierającą imiona osób i ich numery telefonu stacjonarnego oraz komórkowego. Każdy element ma ten sam rozmiar w pamięci. Baza danych ma być umieszczona w pliku binarnym. Wykorzystaj do tego moduły. ZADANIE 3.5.16: Utwórz funkcję modyfikowania pojedynczych wpisów w książce telefonicznej z poprzedniego zadania.
lajd 13 z 13 C++ - [3-5] Pliki i strumienie w C++ Dziękuję za uwagę ŹRÓDŁA WIEDZY: Jerzy Grębosz Symfonia C++ Standard oraz http://cplusplus.com.