Operacje WE/WY Operacje wejścia / wyjścia odczyt i zapis danych do różnych zewnętrznych urządzeń lub nośników pamięciowych komputera: np. klawiatury, ekranu monitora, dyskietki, czytnika taśmy, drukarki, itp. Język C/C++ nie ma wbudowanych żadnych instrukcji umożliwiających wykonywanie operacji wejścia-wyjścia! Służą do tego funkcje biblioteczne. METODY I JĘZYKI PROGRAMOWANIA Programowanie w języku C notatki z wykładów - Operacje WE/WY - Praca z plikami w języku C (biblioteki io oraz stdio) - Obiektowe operacje WE/WY (biblioteka iostream) Operacje na plikach (niskiego poziomu) < IO.H > int open ( char nazwa_pliku, int tryb_dostepu ) int close ( int handle ) int write ( int handle, void adres_bufora, unsigned ilosc_bajtow ) bin. int read ( int handle, void adres_bufora, unsigned ilosc_bajtow ) bin. int eof ( int handle ) long tell ( int handle ) long filelength ( int handle ) long lseek ( int handle, long przesuniecie, int względem_czego ) Proceduralnie za pomocą strumieniu < STDIO.H > FILE fopen ( char nazwa_pliku, char rodzaj_operacji ) int fclose ( FILE strumien ) int fcloseall (void ) int fputc ( int znak, FILE strumien ) txt int fputs ( char tekst, FILE strumien ) txt int fprintf ( FILE strumien, char format,... ) txt int fwrite ( void adres, size_t rozm_bl, size_t il_blokow, FILE strumien ) bin int fgetc ( FILE strumien ) txt char fgets ( char tekst, int dlugosc, FILE strumien ) txt int fscanf ( FILE strumien, char format,... ) txt int fread ( void adres, size_t rozm_bl, size_t il_blokow, FILE strumien ) bin int feof ( FILE strumien ) int fseek ( FILE strumien, long przesuniecie, int wzgledem) long ftell ( FILE strumien ) int fflush ( FILE strumien ) int flushall ( void ) 1 2
Praca z plikami w języku C Język C/C++ nie ma wbudowanych żadnych instrukcji umożliwiających wykonywanie operacji wejścia-wyjścia! Służą do tego funkcje biblioteczne. Funkcje zawarte w bibliotece < io.h > Dostęp do pliku za pomocą uchwytu (ang. Handle) - operacje niskiego poziomu 1. Funkcje otwierania (zwraca uchwyt pliku) oraz zamknięcia pliku int open ( const char nazwa_pliku, int tryb_dostepu ) int close ( int handle ) 2. Funkcje zapisu i odczytu z pliku int write ( int handle, void adres_bufora, unsigned ilosc_bajtow ) int read ( int handle, void adres_bufora, unsigned ilosc_bajtow ); 3. Funkcje pomocnicze int eof ( int handle ) // zwraca 1 gdy END OF FiILE long tell ( int handle ) // zwraca pozycję wskaźnika pliku long filelength ( int handle ) // zwraca długosć pliku w bajtach long lseek ( int handle, long przesuniecie, int względem_czego ) // przesuwa wskaźnik pliku o zadaną ilość bajtów względem zadanego miejsca: SEEK_SET - względem początku pliku SEEK_CUR - względem aktualnej pozycji SEEK_END - względem końca pliku int plik; char tekst[ ] = "To jest tekst zapisywany i odczytywany z pliku"; plik = open( "test.dat", O_CREAT O_RDWR ); write( plik, tekst, strlen( tekst ) ); // zapis zawartosci tekstu do pliku lseek( plik, 0L, SEEK_SET ); // przesuniecie wskaźnika na poczatek do // odczyt po jednym znaku aż do napotkania eof read( plik, &znak, 1); printf( "%c", znak ); // wydruk odczytanego znaku na ekranie while (!eof( plik ) ); close( plik ); Funkcje zawarte w bibliotece < stdio.h > Operacje we/wy realizowane za pomocą strumieni (ang. Stream) Strumienie reprezentowane są przez zmienne typu FILE. Struktura taka tworzona jest automatycznie podczas otwierania strumienia (zawiera informacje o nazwie pliku, trybie otwarcia, itp.). Wszystkie dalsze operacje na strumieniu wymagają podania wskaźnika na tą strukturę. FILE plik_wej, wyniki ; 0. Standardowe strumienie wejścia i wyjscia (otwierane automatycznie) stdin strumień wejściowy (konsola - klawiatura) stdout strumień wyjściowy (konsola - monitor) stderr strumień komunikatów błędów (konsola) stdprn strumień drukarki 1. Funkcje otwarcia (zwraca wskaźnik na FILE) oraz zamknięcia pliku FILE fopen ( char nazwa_pliku, char rodzaj_operacji ) FILE plik; rodzaj operacji: // definicja zmiennych strumieniowych r tylko do odczytu w tylko do zapisu (utworzenie nowego) a dopisywanie na końcu + z mozliwością aktualizacji b otwarcie jako plik binarny t otwarcie jako plik tekstowy // utworzenie pliku binarnego z możliwoscia aktualizacji plik = fopen( a:\wyniki.dat, w+b ); if( plik == NULL ) // kontrola błędów we/wy printf( Blad otwarcia pliku wyników ); exit( 1 ); int fclose ( FILE strumien ) int fcloseall (void ) // zamknięcie wskazanego strumienia // zamknięcie wszystkich strumieni 3 4
2. Zapis danych do strumienia int fputc ( int znak, FILE strumien ) // wysłanie pojedynczego znaku int fputs ( char tekst, FILE strumien ) // wysłanie łańcucha znaków int fprintf ( FILE strumien, char format,... ) // funkcja sformatowanego wyjscia analogiczna do printf( ) int fwrite ( void adres_w_pamieci, size_t rozmiar_bloku, size_t ilosc_blokow, FILE strumien) // funkcja kopiująca (ilosc_blokow rozmiar_bloku) bajtów spod wskazanego obszaru pamięci do strumienia (pliku) #include <stdio.h> struct student char nazwisko[31]; char imie[16]; int wiek; ; FILE *strumien; struct sudent baza_danych[10]; if ( (strumien = fopen( "test.bin", " wb " ) )!= NULL ) // zapis zawartości calej bazy ( tablicy struktur) do pliku binarnego fwrite( baza_danych, sizeof(struct student), 10, strumien); if ( (strumien = fopen( "test.txt", " wt " ) )!= NULL ) // zapis zawartości calej bazy ( tablicy struktur) do pliku tekstowego for( int i = 0; i < 10; i++ ) fprintf ( strumien, %s %s %d \n, baza[ i ].nazwisko, baza[ i ].imie, baza[ i ].wiek ); baza[ i ].nazwisko, Jeżeli jako strumień wyjsciowy podamy stdout (standardowy strumien wyjsciowy) to wtedy wydruk bedzie dokonywany na ekran. np. fprintf( stdout, format,... ) printf( format,... ) 3. Odczyt danych ze strumienia int fgetc ( FILE strumien ) // wczytanie pojedynczego znaku char fgets ( char tekst, int dlugosc, FILE strumien ) // wczytanie łańcucha składającego się z co najwyżej (dlugosc 1) znaków int fscanf ( FILE strumien, char format,... ) // funkcja sformatowanego wejścia analogiczna do scanf( ) int fread ( void adres_w_pamieci, size_t rozmiar_bloku, size_t ilosc_blokow, FILE strumien) // funkcja odczytująca (ilosc_blokow rozmiar_bloku) bajtów ze strumienia do wskazanego obszaru pamięci #include <stdio.h> struct student char nazwisko[31]; char imie[16]; int wiek; ; FILE *strumien; struct sudent baza_danych[10]; int ilosc_osob; if ( (strumien = fopen( "test.bin", " rb " ) )!= NULL ) // wczytanie zawartości bazy ( tablicy struktur) z pliku binarnego ilosc = 0; while( fread( &baza_danych[ilosc], sizeof(student), 1, strumien) == 1) ilosc++; if ( (strumien = fopen( "test.txt", " rt " ) )!= NULL ) // wczytaniet zawartości bazy ( tablicy struktur) z pliku tekstowego for( ilosc = 0; (!feof(strumien) ) && (ilosc <= 10); i++ ) fscanf( strumien, %s %s %d, baza[ i ].nazwisko, baza[ i ].imie, &(baza[ i ].wiek) ); baza[ i ].nazwisko, 5 6
4. Funkcje pomocnicze int feof ( FILE strumien ) // testowanie osiągnięcia końca pliku int fseek ( FILE strumien, long przesuniecie, int wzgledem) // przesuwa wskaźnik pliku o zadaną ilość bajtów względem zadanego miejsca: SEEK_SET - względem początku pliku SEEK_CUR - względem aktualnej pozycji SEEK_END - względem końca pliku long ftell ( FILE strumien ) // zwraca aktualną pozycję wskaźnika pliku int fflush ( FILE strumien ) int fflush ( void ) // wymiata bufor wskazanego strumienia // j.w.dla wszystkich buforowanych strumieni // funkcja wyznaczająca pozycję maksymalnej wartości typu double w pliku binarnym #include <stdio.h> long Maksimum( char nazwa_pliku ) FILE plik_danych; long pozycja=0, poz_max = 1; double liczba, maksimum; if ( (plik_danych = fopen( nazwa_pliku, "rb" ) )!= NULL ) while( fread( &liczba, sizeof(double), 1, plik_danych) == 1) if( pozycja == 0 ) maksimum = liczba; poz_max = 0; else if( liczba > maksimum ) maksimum = liczba; poz_max = pozycja; pozycja++; return( poz_max ); Obiektowe operacje WE/WY (iostream.h) W języku C++ możliwa jest obiektowa realizacja operacji we/wy. Podejście obiektowe zakłada, że różne urządzenia będą reprezentowane w programie za pomocą różnych obiektów modelujących strumienie danych wpływające lub wypływające z tych urządzeń. W obiektowych bibliotekach we/wy zdefiniowano różne klasy obiektów strumieni (w zależności od specyficznych cech danego urządzenia ). Cechy strumienia można odczytać z poszczególne liter nazw klas : i... (in) strumienie wejściowe (np. istream, ifstream, istrstream), o... (out) strumienie wyjściowe (np. ostream, ofstream, ostrstream), f... (file) strumienie plikowe (np. ifstream, ofstream, fstream), str.. (string) strumienie pamięciowe (np. istrstream, strstream), Aby uniknąć wielokrotnego definiowania tych samych operacji (np. dla każdego strumienia musi być funkcja informująca czy wystąpił błąd) klasy strumieni tworzą wielopoziomową hierarchię: PODSTAWOWĄ KLASĄ JEST KLASA ios Modeluje ona właściwości (tzn. funkcje, zmienne i stałe) wspólne dla wszystkich strumieni. Definicja klasy ios jest zawarta w pliku <iostream.h>. int ios::bad( ) - zwraca wartość różną od zera, jeżeli wystąpił błąd, int ios::good( ) - zwraca wartość różną od zera, jeżeli nie było błędu, int ios::eof( ) - zwraca wartość różną od zera, gdy koniec danych, int ios::width( int ) - steruje szerokością pola wyjściowego (np.ilość cyfr) int ios::precision( int ) - steruje ilością cyfr po przecinku Stałe trybów otwarcia strumienia: ios::in - otwórz strumień do odczytu, ios::out - otwórz strumień do zapisu, ios::app - otwórz strumień w trybie dopisywania na końcu, ios::trunc - wyzeruj rozmiar pliku, jeżeli istnieje, ios::binary - otwórz jako strum. binarny (domyślnie strum. tekstowy), Stałe określające pozycję odniesienia (podczas przesuwania pozycji): ios::beg - względem początku pliku, ios::cur - względem pozycji aktualnej, ios::end - względem końca pliku, 7 8
PODSTAWOWE OPERACJE ODCZYTU klasa istream Modeluje ona metody wspólne dla wszystkich strumieni wejściowych z których odczytujemy dane (tekstowe lub binarne). Definicja klasy istream jest zawarta również w pliku <iostream.h>. get( char& znak) - wczytuje jeden znak ze strumienia, getline(char bufor, int max_dlug, char znak_konca) - wczytuje linię znaków, read( char bufor, int ilość_bajtów ) - wczytuje ciąg bajtów do bufora, >> - operator pobrania/odczytu danych ze strumienia tekstowego. PODSTAWOWE OPERACJE ZAPISU klasa ostream Modeluje ona metody wspólne dla wszystkich strumieni wyjściowych do których zapisujemy dane (tekstowe lub binarne). Definicja klasy ostream jest zawarta również w pliku <iostream.h>. put( char& znak) - wysyła jeden znak do strumienia, write(char bufor, int ilość_bajtów) - wysyła ciąg bajtów z bufora do strum. << - operator wysłania/zapisu danych do strumienia tekstowego. STRUMIENIE STANDARDOWE W programach napisanych w języku C++ można korzystać z czterech predefiniowanych, zawsze otwartych strumieni standardowych: cin - standardowy strumień wejściowy - klawiatura - (istream), cout - standardowy strumień wyjściowy - ekran - (ostream), cerr - strumień komunikatów błędów - zazwyczaj ekran - (ostream), PORÓWNANIE WE/WY «proceduralnego» i «obiektowego» // podejście proceduralne # include <stdio.h> int x; long y; double z; char tekst[ 20 ]; scanf( "%c", &znak ); scanf( "%d", &x ); scanf( "%ld", &y ); scanf( "%lf", &z ); scanf( "%19s", tekst ); printf( "znak = %c \n", znak ); printf( "int = %d \n", x ); printf( "long = %d \n", y ); printf( "double = %f \n", z ); printf( "tekst = %s \n", tekst ); Wczytywanie danych z klawiatury i wydruk na ekranie STRUMIENIE PLIKOWE klasa fstream // podejście obiektowe # include <iostream.h> int x; long y; double z; char tekst[ 20 ]; cin >> znak; // cin.get(znak); cin >> x; cin >> y; cin >> z; cin >> tekst; //cin.getline(tekst,19) cout << "znak =" << znak << "\n"; cout << "int =" << x << "\n"; cout << "long =" << y << "\n"; cout << "double = " << z << "\n"; cout << "tekst = " << tekst << "\n"; Klasa fstream jest klasą pochodną od klas iostream (istream + ostream) oraz fstreambase. Jej definicja zawarta jest w pliku <fstream.h>. void open( char nazwa_pliku, int tryb_otwarcia ) - otwarcie pliku, void close( void ) - zamknięcie pliku skojarzonego ze strumieniem Oraz metody dziedziczone przez fstream z klas podstawowych: z klasy ios fail, good, eof, width, precision z klasy istream get, getline, read, << z klasy ostream put, write, >> 9 10
Kopiowanie plików tekstowych z jednoczesną zamianą liter na duże // podejście proceduralne # include <stdio.h> # include <ctype.h> FILE wej, wyj; wej = fopen( "dane.dat", "rt" ); wyj = fopen( "wyniki.dat", "wt" ); if( (wej!=null) && (wyj!=null) ) while(!feof(wej) ) znak = fgetc(wej); znak = toupper(znak); fputc( znak,wyj ); fclose( wej ); fclose( wyj ); // podejście obiektowe # include <fstream.h> # include <ctype.h> fstream wej,wyj; wej.open( "dane.dat", ios::in ); wyj.open( "wyniki.dat", ios::out ); if( wej.good( ) && wyj.good( ) ) while(! wej.eof( ) ) wej.get( znak ); znak = toupper( znak ); wyj.put( znak ); wej.close( ); wyj.close( ); // funkcja wyznaczająca pozycję maksymalnej wartości typu double w pliku binarnym # include <fstream.h> # include <values.h> double POZYCJA_MAKSIMUM( char nazwa_pliku ) long licznik=0, pozycja=0; double liczba, max = -MAXDOUBLE; fstream plik( nazwa_pliku, ios::in ios::binary ); while( plik.good( ) &&!plik.eof( ) ) plik.read( (char*)&liczba, sizeof(double) ); licznik++; if( liczba>max ) max=liczba; pozycja=licznik; plik.close( ); return( pozycja ); 11