Politechnika Białostocka Wydział Elektryczny Katedra Elektrotechniki Teoretycznej i Metrologii Instrukcja do pracowni specjalistycznej z przedmiotu Informatyka 2 Kod przedmiotu: ES1C300 016 (studia stacjonarne) Spis treści 1. Opis stanowiska... 3 1.1. Stosowana aparatura... 3 1.2. Oprogramowanie... 3 2. Wiadomości teoretyczne... 3 2.1. Schemat przetwarzania pliku... 3 2.2. Otwarcie i zamknięcie pliku (strumienia)... 4 2.3. Formatowane operacje wejścia-wyjścia... 8 2.4. Nieformatowane operacje wejścia-wyjścia... 11 3. Przebieg ćwiczenia... 14 4. Literatura... 15 OBSŁUGA PLIKÓW W JĘZYKU C++ 5. Wymagania BHP... 16 Numer ćwiczenia INF32 Materiały dydaktyczne przeznaczone dla studentów Wydziału Elektrycznego PB. Autor: dr inż. Jarosław Forenc Białystok 2014 Wydział Elektryczny, Politechnika Białostocka, 2014 (wersja 1.0) Wszelkie prawa zastrzeżone. Żadna część tej publikacji nie może być kopiowana i odtwarzana w jakiejkolwiek formie i przy użyciu jakichkolwiek środków bez zgody posiadacza praw autorskich. Informatyka 2 2 z 17 Instrukcja INF32
1. Opis stanowiska 1.1. Stosowana aparatura Podczas zajęć wykorzystywany jest komputer klasy PC z systemem operacyjnym Microsoft Windows (XP/Vista/7). 1.2. Oprogramowanie Na komputerach zainstalowane jest środowisko programistyczne Microsoft Visual Studio 2008 Standard Edition lub Microsoft Visual Studio 2008 Express Edition zawierające kompilator Microsoft Visual C++ 2008. 2. Wiadomości teoretyczne 2.1. Schemat przetwarzania pliku Do przetwarzania plików w języku C++ stosowane są strumienie zrealizowane w postaci klas. Do podstawowych klas należą: - ofstream (output file stream) - klasa zapewniająca zapis do pliku; - ifstream (input file stream) - klasa zapewniająca odczytywanie pliku; - fstream (file stream) - klasa zapewniająca zapis i odczytywanie pliku. Zastosowanie powyższych klas wymaga dołączenia w programie pliku nagłówkowego fstream. Nazwy zadeklarowane w tym pliku wchodzą w skład przestrzeni nazw std. Dodanie dyrektywy using namespace std; spowoduje brak konieczności dodawania kwalifikatora zakresu std:: przed każdą nazwą. #include <iostream> #include <fstream> using namespace std; Rys. 1. Uproszczona hierarchia klas strumieni w języku C++ [1] Zazwyczaj operacje związane z przetwarzaniem pliku składają się z czterech etapów: 1. Zdefiniowanie strumienia czyli stworzenie obiektu jednej z klas: ifstream, ofstream, fstream. 2. Otwarcie pliku (określenie z jakim plikiem strumień ma komunikować się). 3. Wykonanie operacji na pliku. 4. Zamknięcie pliku (zlikwidowanie strumienia). 2.2. Otwarcie i zamknięcie pliku (strumienia) Strumień można otworzyć albo za pomocą konstruktora danej klasy albo wywołując jej funkcję składową open(). Konstruktor i funkcja open() mają dokładnie takie same argumenty. Na Rys. 1 przedstawiona jest uproszczona hierarchia klas strumieni stosowanych w języku C++. Informatyka 2 3 z 17 Instrukcja INF32 Informatyka 2 4 z 17 Instrukcja INF32
open() void open(const char *fname, ios_base::openmode mode); - pierwszy argument (fname) jest nazwą pliku z ewentualną ścieżką dostępu podaną w postaci tablicy znaków zakończonej \0 (C-string); - mode określa tryb pracy z plikiem (rodzaj dostępu do pliku); jako tryb może występować: o in (input) - otwarcie pliku do czytania; o out (output) - otwarcie pliku do pisania; o ate (at end) - otwarcie pliku i ustawienie na jego końcu; o app (append) - otwarcie pliku do dopisywania na jego końcu; o trunc (truncate) - otwarcie pliku i skasowanie aktualnej zawartości; o binary (binary) - otwarcie pliku w trybie binarnym (domyślnie plik jest otwierany w trybie tekstowym); - wszystkie tryby zebrane są w klasie ios_base; tryby można stosować pojedynczo lub po kilka równocześnie, łącząc je bitowym operatorem alternatywy - (często stosowane tryby otwarcia przedstawia Tabela 1); Tryb ios::in ios:out ios::in ios:out Tabela 1. Tryby otwarcia pliku Opis - otwarcie pliku do odczytu - tryb może być zastosowany tylko dla strumieni z klas ifstream i fstream - otwierany plik musi już istnieć - otwarcie pliku do zapisu - tryb może być zastosowany tylko dla strumieni z klas ofstream i fstream - jeśli plik nie istnieje, to zostanie utworzony - jeśli plik istnieje, to jego stara zawartość zostanie usunięta - otwarcie pliku do czytania i pisania - otwierany plik musi już istnieć ios::ate ios::app ios::trunc ios::binary - po otwarciu pliku (do czytania lub pisania) wskaźnik ustawia się na koniec pliku - dotychczasowa zawartość pliku nie jest usuwana - otwarcie pliku do dopisywania na jego końcu - domyślnie, niejawnie, dodawany jest tryb ios:out - jeśli plik nie istnieje, to zostanie utworzony - jeśli plik istnieje, to jego dotychczasowa zawartość zostanie usunięta - tryb ten jest domyślnie zakładany, gdy zastosowano tryb ios::out bez ios::app lub ios::ate - włączenie trybu binarnego - w klasie ifstream domyślnym trybem otwarcia jest ios::in, zaś w klasie ofstream - ios::out; Tabela 2 pokazuje powiązania pomiędzy trybami otwarcia stosowanymi w języku C++ i w języku C. Tabela 2. Tryby otwarcia pliku w języku C++ i w języku C [1] Suma trybów w języku C++ in out trunc app binary Tryb w języku C + w + + a + + w + r + + r+ + + + w+ + + wb + + + ab + + + wb + + rb + + + r+b + + + + w+b Informatyka 2 5 z 17 Instrukcja INF32 Informatyka 2 6 z 17 Instrukcja INF32
Poniżej zamieszczono przykłady otwarcia plików. ofstream ofs; ofs.open("dane.txt"); - wywołanie funkcji składowej open() z klasy ofstream w celu otwarcie pliku dane.txt w trybie tekstowym (domyślny tryb) do zapisu (ios::out - domyślny tryb dla klasy ofstream); ifstream ifs("dane.txt"); Zamknięcie pliku odbywa się poprzez wywołanie metody close(). close() void close(); - funkcja close() zamyka plik skojarzony z otwartym strumieniem. ofstream ofs; ofs.open("dane.txt"); // operacje na pliku ofs.close(); - zastosowanie konstruktora klasy ifstream w celu otwarcie pliku dane.txt w trybie tekstowym (domyślny tryb) do odczytu (ios::in - domyślny tryb dla klasy ifstream); ifstream ifs; ifs.open("d:\\doc\\dane.dat",ios::in ios::binary); - otwarcie pliku dane.dat znajdującego się na dysku D: w folderze doc do odczytu (ios::in) w trybie binarnym (ios::binary); ofstream ofs; string fname("d:\\doc\\dane.txt"); ofs.open(fname.c_str(),ios::out); - otwarcie pliku dane.txt znajdującego się na dysku D: w folderze doc do zapisu (ios::out) w trybie tekstowym (domyślny tryb); - nazwa otwieranego pliku przechowywana jest w obiekcie fname klasy string, zaś funkcja open() wymaga argumentu typu char * (C-string); w celu zapewnienia zgodności typów wywoływana jest funkcja c_str() zwracająca tekst przechowywany w obiekcie w postaci tablicy znaków (C-string). 2.3. Formatowane operacje wejścia-wyjścia Klasa ofstream jest pochodną klasy ostream, klasa ifstream jest pochodną klasy istream, zaś klasa fstream jest pochodną klasy iostream (Rys. 1). Oznacza to, ze wszystko co dotyczyło strumieni iostream (manipulatory, operatory << i >>) dotyczy także operacji na plikach. W poniższym programie zapisywane są do macierzy wygenerowane pseudolosowo liczby zmiennoprzecinkowe typu float z zakresu (-50, 50). Następnie elementy macierzy zapisywane są do pliku tekstowego liczby.txt (z podziałem na wiersze i kolumny oraz z dokładnością do trzech cyfr po kropce dziesiętnej). Zapisanie liczb zmiennoprzecinkowych do macierzy i pliku tekstowego. #include <iostream> #include <fstream> #include <iomanip> #include <ctime> using namespace std; #define N 4 #define M 5 Informatyka 2 7 z 17 Instrukcja INF32 Informatyka 2 8 z 17 Instrukcja INF32
int main() float T[N][M]; int i, j; ofstream ofs; ofs.open("liczby.txt"); if (!ofs) cout << "Blad otwarcia pliku!" << endl; return 0; srand((unsigned int)time(null)); for (i=0; i<n; i++) for (j=0; j<m; j++) T[i][j] = 100*(float)rand()/RAND_MAX - 50; ofs << fixed << setprecision(3); for (i=0; i<n; i++) for (j=0; j<m; j++) ofs << setw(10) << T[i][j]; ofs << endl; ofs.close(); Zapis do pliku odbywa się za pośrednictwem strumienia ofs. Sposób formatowania liczb w pliku określają manipulatory fixed, seprecision() i setw(). Przykładowa zawartość pliku liczby.txt: -34.048-24.453 21.288 17.876 4.579 31.423-9.053 39.438 21.139 19.475-30.712 9.923-5.895 44.351-27.886 42.730-49.066-29.186 13.762 18.917 Kolejny program wyświetla na ekranie zawartość pliku liczby.txt. Wyświetlenie liczb zmiennoprzecinkowych odczytanych z pliku tekstowego. #include <iostream> #include <fstream> #include <iomanip> using namespace std; #define N 4 #define M 5 int main() int i, j; float x; ifstream ifs; ifs.open("liczby.txt"); if (!ifs) cout << "Blad otwarcia pliku!" << endl; return 0; cout << fixed << setprecision(3); for (i=0; i<n; i++) for (j=0; j<m; j++) ifs >> x; cout << setw(10) << x; cout << endl; ifs.close(); Jeśli nie jest znana ilość liczb zapisanych w pliku, to można je wszystkie odczytać i wyświetlić na ekranie stosując jedną pętlę while. while (ifs >> x) cout << setw(10) << x; Informatyka 2 9 z 17 Instrukcja INF32 Informatyka 2 10 z 17 Instrukcja INF32
2.4. Nieformatowane operacje wejścia-wyjścia Stosując operatory << i >> można formatować sposób wprowadzania i wyprowadzania danych do pliku. Opisane w tym rozdziale funkcje nie wpływają w żaden sposób na przetwarzane dane. Funkcje te mogą być stosowane zarówno do standardowych strumieni (cin i cout) jak i do strumieni skojarzonych z plikami. get() istream & get(char & c); - funkcja get() pobiera ze strumienia jeden bajt i umieszcza go w zmiennej c; get() int get(); - w tej postaci funkcja get() wczytuje ze strumienia jeden znak i zwraca go; int c; c = cin.get(); get() istream & get(char * s, streamsize n, char delim= \n ); char c; cin.get(c); - funkcja get() zwraca referencję do strumienia, na którym pracuje, co umożliwia jej kaskadowe wywołanie; char a, b, c; cin.get(a).get(b).get(c); - jeśli odczytanym znakiem będzie znak końca pliku danych, to funkcja zwraca 0 (NULL); - odczytanie kolejnych znaków z pliku i wyświetlenie ich na ekranie może mieć następującą postać: char c; ifstream ifs("liczby.txt"); while(ifs.get(c)!= 0) cout << c; ifs.close(); - w tej postaci funkcja get() czyta ze strumienia n-1 znaków lub znaki do momentu wystąpienia ogranicznika delim (ogranicznik nie jest czytany i pozostaje w strumieniu); - przeczytane znaki są umieszczane w tablicy s, na końcu której zapisywany jest bajt zerowy kończący C-string ( \0 ); - funkcja get() zwraca referencję do strumienia, z którym pracuje, a jeśli podczas czytania wystąpi znak końca pliku danych, to zwraca 0; char txt[10]; cin.get(txt,10); getline() istream & getline(char * s, streamsize n, char delim= \n ); - funkcja getline() działa identycznie jak get() w ostatnio opisanej postaci, ale ogranicznik delim jest pobierany ze strumienia i wyrzucany; - jeśli wczytywanie zostanie zatrzymane z powodu przekroczenia liczby znaków n, to strumień sygnalizuje błąd - tzw. failbit; read() istream & read(char * s, streamsize n); - funkcja read() odczytuje ze strumienia n bajtów i umieszcza je w tablicy s; Informatyka 2 11 z 17 Instrukcja INF32 Informatyka 2 12 z 17 Instrukcja INF32
- funkcja ta może być zastosowana do odczytania zawartości pliku binarnego; - jeśli odczytywany jest obiekt innego typu niż char, to należy dokonać odpowiedniego rzutowania do typu char *; readsome() streamsize & readsome(char * s, streamsize n); - funkcja readsome() działa tak samo jak read(), ale n oznacza maksymalną liczbę bajtów, które należy odczytać ze strumienia; - jeśli zostanie odczytanych mniej bajtów, to nie ma sygnalizacji błędu, a liczba faktycznie przeczytanych bajtów jest zwracana przez funkcję; gcount() streamsize gcount(); - funkcja gcount() zwraca liczbę znaków przeczytanych ze strumienia za pomocą ostatniej funkcji wczytywania nieformatowanego (czyli nie przez operator >>); put() ostream & put(char c); - funkcja put() wstawia do strumienia znak c; - jeśli operacja nie może się udać, to zamiast referencji do strumienia, na którym pracuje, zwraca wartość zero (0); write() ostream & write(const char *s, streamsize n); - funkcja write() pobiera z tablicy s n bajtów i wstawia je do strumienia; - jeśli operacja nie może się udać, to zamiast referencji do strumienia, na którym pracuje, zwraca wartość zero (0); char txt[10] = "Napis"; cout.write(txt,5); - jeśli mamy obiekt innego typu niż char, to należy dokonać odpowiedniego rzutowania do typu char *; - w poniższym przykładzie do pliku binarnego zapisywana jest wartość zmiennej x1 typu float, a następnie plik jest zamykany; po ponownym otwarciu pliku, zapisana w nim liczba jest odczytywana i wyświetlana na ekranie; float x1 = 100, x2; ofstream ofs("dane.dat",ios::binary); ofs.write((char *) &x1,sizeof(x1)); ofs.close(); ifstream ifs("dane.dat",ios::binary); ifs.read((char *) &x2,sizeof(x2)); ifs.close(); cout << "x1 = " << x1 << " x2 = " << x2 << endl; 3. Przebieg ćwiczenia Na pracowni specjalistycznej należy wykonać wybrane zadania wskazane przez prowadzącego zajęcia. W różnych grupach mogą być wykonywane różne zadania. 1. Napisz program zapisujący do pliku tekstowego vcard.txt wizytówkę o poniższej postaci. ******************************** * Jan Kowalski * * e-mail: j.kowalski@gmail.com * * tel. 123-456-789 * ******************************** 2. W pliku tekstowym pomiar.txt znajdują się dwie kolumny liczb rzeczywistych zawierające wyniki pomiarów wartości chwilowych napięcia i prądu. Napisz program, który odczyta zawartość pliku pomiar.txt i na jego podstawie utworzy plik moc.txt zawierający trzy kolumny liczb oznaczające: wartość chwilową Informatyka 2 13 z 17 Instrukcja INF32 Informatyka 2 14 z 17 Instrukcja INF32
napięcia, wartość chwilową prądu, wartość chwilową mocy. Plik pomiar.txt wskaże prowadzący zajęcia. 3. Plik binarny hdd.dat zawiera struktury dysk opisujące dysk twardy. Kolejne pola struktury opisują: producenta, model, pojemność (w GB), prędkość obrotową (w obr/min), cenę (w PLN). Plik hdd.dat wskaże prowadzący zajęcia. struct dysk char producent[20]; char model[20]; int pojemnosc; int predkosc; int cena; ; Napisz program, który odczyta zawartość pliku i wyświetli dane o dyskach na ekranie. 4. Literatura [1] Grębosz J.: Symfonia C++ standard: programowanie w języku C++ orientowane obiektowo. Tom 1 i 2. Wydawnictwo Edition 2000, Kraków, 2008. [2] Stroustrup B.: Programowanie. Teoria i praktyka z wykorzystaniem C++. Wydanie II poprawione. Helion, Gliwice, 2013. [3] Eckel B.: Thinking in C++. Edycja polska. Helion, Gliwice, 2002. [4] Prata S.: Język C++. Szkoła programowania. Wydanie VI. Helion, Gliwice, 2012. [5] http://www.cplusplus.com/reference/ - C++ Reference 5. Zagadnienia na zaliczenie 1. Opisz schemat przetwarzania pliku w języku C++. 2. Scharakteryzuj tryby otwarcia pliku (strumienia) stosowane w klasie ios_base. 3. Opisz sposoby wykrywania końca pliku przy odczytywaniu z niego danych. 6. Wymagania BHP Warunkiem przystąpienia do praktycznej realizacji ćwiczenia jest zapoznanie się z instrukcją BHP i instrukcją przeciw pożarową oraz przestrzeganie zasad w nich zawartych. W trakcie zajęć laboratoryjnych należy przestrzegać następujących zasad. - Sprawdzić, czy urządzenia dostępne na stanowisku laboratoryjnym są w stanie kompletnym, nie wskazującym na fizyczne uszkodzenie. - Jeżeli istnieje taka możliwość, należy dostosować warunki stanowiska do własnych potrzeb, ze względu na ergonomię. Monitor komputera ustawić w sposób zapewniający stałą i wygodną obserwację dla wszystkich członków zespołu. - Sprawdzić prawidłowość połączeń urządzeń. - Załączenie komputera może nastąpić po wyrażeniu zgody przez prowadzącego. - W trakcie pracy z komputerem zabronione jest spożywanie posiłków i picie napojów. - W przypadku zakończenia pracy należy zakończyć sesję przez wydanie polecenia wylogowania. Zamknięcie systemu operacyjnego może się odbywać tylko na wyraźne polecenie prowadzącego. - Zabronione jest dokonywanie jakichkolwiek przełączeń oraz wymiana elementów składowych stanowiska. Informatyka 2 15 z 17 Instrukcja INF32 Informatyka 2 16 z 17 Instrukcja INF32
- Zabroniona jest zmiana konfiguracji komputera, w tym systemu operacyjnego i programów użytkowych, która nie wynika z programu zajęć i nie jest wykonywana w porozumieniu z prowadzącym zajęcia. - W przypadku zaniku napięcia zasilającego należy niezwłocznie wyłączyć wszystkie urządzenia. - Stwierdzone wszelkie braki w wyposażeniu stanowiska oraz nieprawidłowości w funkcjonowaniu sprzętu należy przekazywać prowadzącemu zajęcia. - Zabrania się samodzielnego włączania, manipulowania i korzystania z urządzeń nie należących do danego ćwiczenia. - W przypadku wystąpienia porażenia prądem elektrycznym należy niezwłocznie wyłączyć zasilanie stanowiska. Przed odłączeniem napięcia nie dotykać porażonego. Informatyka 2 17 z 17 Instrukcja INF32