Pobierz prezentację
Pobieranie prezentacji. Proszę czekać
1
Operacje na plikach w C++
2
Wprowadzenie Było – dane są przechowywane w pamięci operacyjnej, programy także. Wniosek – dane „żyją” tylko i wyłącznie w czasie pracy programu. Potem są nieodwołalnie usuwane. Problem – co z danymi, których jest tak dużo, że nie warto ich wprowadzać za każdym uruchomieniem programu – np. dane PESEL, Rozwiązaniem jest wykorzystanie plików.
3
Wprowadzenie Co to jest plik? Jaka jest organizacja pliku?
Plik jest to zorganizowana struktura przechowywania informacji w sposób trwały. Jaka jest organizacja pliku? Fizyczna, Logiczna. Fizyczna nas (w tej chwili) nie interesuje - ścieżki, sektory, cylindry, rekordy (zazwyczaj 512B) itd. Logiczna – system plików i katalogów. By w programowaniu korzystać z plików musimy orientować się w strukturze logicznej plików, czyli znać hierarchiczną strukturę plików na komputerze, na którym programujemy. Hierarchiczna struktura plików to katalogi (katalog główny, bieżący, podkatalogi) i pliki w katalogach. Katalog jest to taki plik, który może zawierać inne pliki.
4
Model pliku w programowaniu
W pewnym uproszczeniu każdy plik możemy wyobrazić sobie jako ciąg kolejnych elementów. Za ostatnim znajduje się znacznik końca pliku. Element który zostanie przeniesiony z lub do RAM przy kolejnym odczycie lub zapisie wskazywany jest przez wskaźnik pliku stojący na początku tego elementu. Wskaźnik końca może być realizowane na różne sposoby. Czasami jest to wyróżniona wartość (inna niż dowolna przechowywana w pliku informacja) zapisana na końcu pliku, a w innych rozwiązaniach informacja o końcu pliku zapisana jest w strukturze systemu zbiorów zwanej FAT (ang. file allocation table).
5
Typy plików Ze względu na organizacje danych wewnątrz pliku (na poziomie logicznym), będziemy rozróżniać dwa typy plików: pliki binarne i pliki tekstowe.
6
Pliki tekstowe Pliki tekstowe zasługują na szczególną uwagę, gdyż sposób kodowania informacji w tych plikach jest najbardziej rozpowszechnionym standardem, a także dlatego, że w wielu językach programowania stanowią one osobny wyróżniony typ danych z dodatkowym zestawem poleceń. Plik tekstowy to ciąg znaków z podziałem na wiersze. Można powiedzieć, że podstawową jednostką danych w pliku tekstowym jest jeden znak, co w plikach zakodowanych w ASCII przekłada się na 1 bajt (nie zawsze). Koniec wiersza kodowany jest na różne sposoby. Np. w systemie UNIX znak przejścia do nowego wiersza, a w systemie MS Windows koniec wiersza oznaczony jest dwoma znakami przejściem do nowego wiersza i powrotem karetki. Są ważne.
7
Pliki binarne Plik binarny to ciąg bajtów.
Inaczej można powiedzieć, że jest to plik, w którym rekord logiczny ma rozmiar jednego bajta. Dane zawarte w pliku binarnym zawsze traktowane są jak ciąg bajtów, bez względu na rodzaj zapisanej w pliku informacji. Każdy plik możemy potraktować jak plik binarny. Musi być program, który te bajty interpretuje (w plikach tekstowych wszystkie bajty są znakami drukowalnymi (poza znakiem przejścia do nowego wiersza).
8
Rodzaje dostępu do pliku
Budowa pamięci masowej może też powodować ograniczenia w sposobie dostępu do poszczególnych części pliku. Ze względu na te ograniczenia pliki możemy podzielić na: pliki sekwencyjne, pliki o dostępie bezpośrednim.
9
Pliki o dostępie sekwencyjnym
Pliki o dostępie sekwencyjnym charakteryzują się ograniczoną swobodą poruszania się po rekordach. Aby przeczytać k-ty rekord trzeba przeczytać poprzedzające go k-1 rekordów. Dodatkowo możemy przeskoczyć na początek albo na koniec pliku, ale nigdy w dowolne miejsce wewnątrz pliku.
10
Pliki o dostępie bezpośrednim
Pliki o dostępie bezpośrednim charakteryzują się tym, że rekordy logiczne są ponumerowane i można odczytywać je w dowolnym porządku dzięki operacji pozwalającej na przeskoczenie do rekordu o podanym numerze. W tego rodzaju plikach wszystkie rekordy logiczne muszą mieć taki sam rozmiar. Pliki o dostępie bezpośrednim realizuje się na takich urządzeniach, w których łatwo można się fizycznie dostać do dowolnego miejsca, niezależnie od jego położenia. Przykładami takich urządzeń są twarde dyski, pamięci flash.
11
Schemat przetwarzanie plików
Otwarcie pliku, Operacje na danych w pliku, Zamknięcie pliku. Uwaga1: w języku C++ za pracę z plikami odpowiada biblioteka fstream. Zawiera ona predefiniowane stałe i zdefiniowane funkcje ułatwiające operacje na plikach. Uwaga2: ważne typy danych związanych z plikami: fstream – dowolny pliki, ofstream – plik do zapisu, ifstream – plik do odczytu.
12
Przykład #include <fstream> #include <iostream>
using namespace std; int main(){ ofstream strumien; //definicja strumienia strumien.open("plik.txt"); //wskazanie pliku strumien << "Zapis do pliku"; //przeprowadzenie operacji (zapis) strumien.close(); //zamknięcie strumienia (następuje zapis do pliku, strumień jest buforowany) } Uwaga: Nie zamkniecie pliku może prowadzić do utraty danych. Dlaczego? – bo zapis jest buforowany.
13
Co trzeba zrobić, by pracować z plikami w C++
Aby korzystać z plików należy dołączyć plik nagłówkowy fstream.h dyrektywą include: #include <fstream> Aby otworzyć plik do pisania, należy zdefiniować obiekt klasy ofstream (output file stream), np. ofstream plikwy(”nazwapliku”,ios::out); Użyte argumenty oznaczają: nazwapliku – nazwę pliku, ios::out – tryb otwarcia tego pliku. Do odczytu to ios::in Innym trybem może być ios::app – dla dodawania nowych elementów do pliku. Gdy chcemy dopisywać nowe elementy, to należy użyć trybu ios::app. Gdy chcemy by plik był pusty po utworzeniu, to używamy ios::trunc, Typ pliku binarny to ios::binary, a tekstowy to ios::text.
14
Sprawdzenie, czy operacja otwarcia pliku się udała
Dobrym zwyczajem jest sprawdzenie (przed próbą pisania lub czytania), czy plik został pomyślnie otwarty. Można to zrobić następująco: if (!plikwy) { // nie udało się otworzyć pliku cerr<<”nie można otworzyć pliku wyjściowego”; exit (-1); } cerr jest standardowym urządzeniem na które są wysyłane komunikaty o błędach. Domyślnie jest to ekran (podobnie jak i cout). Sprawdzać można także za pomocą funkcji: good(); is_open(); Sa to funkcje, które zwracają prawdę lub fałsz
15
Przykład fstream plik; plik.open( "nazwa_pliku.txt", std::ios::in | std::ios::out ); if( plik.good() ) cout << "Uzyskano dostep do pliku! "; else cout << " Nie uzyskano dostepu ";
16
Przykład Przykład programu pobierającego znaki ze standardowego strumienia wejściowego i wysyłającego do pliku kopia (domyślnym typem pliku jest plik tekstowy) #include <iostream> #include <fstream> main() { ofstream plikwy(”nazwapliku”,ios::out); if (!plikwy) { // nie udało się otworzyć pliku cerr<<”nie można otworzyć pliku wyjściowego”; exit (-1); } char zn; while (cin.get(zn)) plikwy.put(zn); return 0;
17
Czytanie z pliku nazwa >> zmienna; //wczytanie zmiennej
getline( plik, dane ); //wczytanie wiersza istream plik.getline( char * odczytane_dane, streamsize ilosc_danych, char znak_konca_linii ); Parametry oznaczają kolejno: (odczytane_dane) wskaźnik zmiennej, do której mają zostać wczytane dane z pliku; (ilosc_danych) maksymalna ilość znaków jakie mogą zostać zapisane do zmiennej; (znak_konca_linii) parametr jest opcjonalny. Umożliwia zmianę znaku końca linii. Przykład: fstream plik( „dane.txt", ios::in ); char dane[ 255 ]; plik.getline( dane, 255 );
18
Czytanie blokowe z pliku
Czytanie blokowe z pliku jest bezpieczne dla typu binary. istream plik.read( char * bufor, streamsize rozmiar_bufora ); Bufor nie musi być wypełniony cały danymi. Do sprawdzenia, ile danych było w buforze służy funkcja gcount(), Przykład: fstream plik( "nazwa_pliku.txt", std::ios::in ); char bufor[ 1024 ]; plik.read( bufor, 1024 ); cout << "Wczytano " << plik.gcount() << " bajtów”;
19
Zapisywanie danych do pliku
ostream plik.write( const char *bufor, streamsize ilosc); fstream plik( "plik.txt", ios::out ); string napis; getline(cin, napis ); plik.write( &napis[ 0 ], napis.length() ); //zapisuje //dane poczynając od 0 indeksu
20
Poruszanie się po pliku
Do tego celu służą funkcje seekg() i seekp() seekg() ustawia wewnętrzny wskaźnik pliku dla funkcji odczytujących dane; seekp() ustawia wewnętrzny wskaźnik pliku dla funkcji zapisujących dane. Uzycie: istream p.seekg( streamoff offset, ios_base::seekdir kierunek ); ostream p.seekp( streamoff offset, ios_base::seekdir kierunek ); Dla kierunek sa możliwości: ios_base::beg - Przesunięcie względem początku pliku (domyślne) ios_base::cur - Przesunięcie względem aktualnej pozycji ios_base::end - Przesunięcie względem końca pliku
21
Poruszanie się po pliku
Aby sprawdzić, czy skok na nową pozycję zakończył się sukcesem możemy dokonać tego na dwa sposoby: Sprawdzić aktualną pozycję pliku i porównać z tą, którą chcieliśmy otrzymać; Wywołać funkcję fail(), należącą do klasy fstream. Jest ona postaci: fail(); i zwraca wartość logiczną. Do testowania końca pliku służy funkcja plik.eof()
22
Przykład – czytanie znaków i wyrazów
// #include <conio.h> #include <iostream.h> #include <fstream.h> int main(int argc, char* argv[]) { ofstream zapis; ifstream odczyt; zapis.open("c:\\plik1.doc",ios::out); if ( !zapis ) cerr << "Nieudane otwarcie pliku do zapisu\n"; getch(); exit( 1 ); } zapis << "To jest pierwszy wiersz tekstu, \n"; zapis << "a to drugi.\n"; char napis[20]; cout<<"napis="; cin>>napis; zapis << napis; zapis.close(); odczyt.open("c:\\plik1.doc",ios::in); char znak; while ((znak=odczyt.get())!=EOF) cout<<znak; cout<<"Koniec"; odczyt.close(); return 0;
23
Przykład – czytanie liczb
#include <vcl.h> #include <iostream.h> #include <fstream.h> #include <conio.h> #pragma hdrstop #pragma argsused int main(int argc, char* argv[]) { float liczba=1.0; fstream plik("c:\\liczby.txt",ios::in | ios::out | ios::trunc); while(true){ cout << "Podaj liczbe: "; cin >> liczba; if(liczba!=0) plik << liczba << " "; else break; } plik.close(); plik.open("c:\\liczby.txt"); while(!plik.eof()){ plik>>liczba; if(!plik.fail()) cout<<liczba<<" "; //ostatnim znakiem jest spacja, wiec eof jest dopiero po spacji cout<<endl; getch(); return 0; Uwaga: Funkcja int fail() - funkcja zwraca wartość niezerową np. gdy oczekujemy wartości liczbowej a otrzymamy tekst
24
Wszystkie tryby otwarcia pliku
app - otwarcie pliku do dopisywania, dane dołączane są do końca pliku. ate - otwarcie pliku z ustawieniem wskaźnika plikowego na końcu pliku. in - otwarcie pliku do odczytu (tryb domyślny klasy ifstream) out - otwarcie pliku do zapisu (tryb domyślny klasy ofstream) binary - otwarcie pliku w trybie binarnym. Pliki obsługiwane są za pomocą klas ifstream i ofstream otwierane są domyślnie w trybie tekstowym, trunc - Otwarcie pliku ze zniszczeniem jego poprzedniej zawartości. Tryb ten jest domyślny, o ile nie został użyty specyfikator app lub ate.
25
Zapis do plików binarnych
#include <iostream.h> #include <fstream.h> int main(int argc, char* argv[]) { struct firmy{ char* nazwa; float przychod; }; //zapis danych firmy firma; ofstream plik1("dane.dat",ios::binary | ios::app| ios::out); firma.nazwa="test"; firma.przychod=23; // zapis do pliku struktury firma przekonwertowanej (przeinterpretowanej) na ciąg znaków // ponieważ jest ios::app to dopisujemy na końcu pliku plik1.write(reinterpret_cast<char*>(&firma),sizeof(firma)); plik1.close(); plik.close(); getchar(); return 0; } //
26
Odczyt danych z pliku binarnego
#include <iostream.h> #include <fstream.h> int main(int argc, char* argv[]) { struct firmy{ char* nazwa; float przychod; }; //odczyt danych int i=1; ifstream plik("dane.dat",ios::binary| ios::in); while (1) // odczyt z pliku ciągu znaków i przekonwertowanie (przeinterpretowanie) na ciąg strukturę firma plik.read(reinterpret_cast<char*>(&firma),sizeof(firma)); //z plikiem związany jest znacznik pliku. Znacznik pliku może by na końcu, //ale funkcja eof() zwróci wartosc false. //Funkcja zwróci wartosc true gdy znacznik jest na końcu pliku i jeszcze cos czytamy. if(plik.eof()) break; //tu jestesmy, gdy czytanie powiodło się, więc to co przeczytalismy wypisujemy. cout<<i<<" "<<firma.nazwa<<" "<<firma.przychod<<endl; i++; } plik1.close(); plik.close(); getchar(); return 0;
27
Operator reinterpret_cast
Zapis <T> oznacza szablon – jest to pojecie z programowania obiektowego. reinterpret_cast< T > (arg) to operator, którego celem jest konwersja przez zamianę typów, które są niepewne (nie mamy pewności co do konwersji niejawnej dokonanej przez kompilator) lub zależne od implementacji. W deklaracji, reinterpret_cast< T > (arg) , T musi być wskaźnikiem, referencją, typem arytmetycznym, wskaźnikiem na funkcję lub wskaźnikiem na element. Wskaźnik może być całkowicie przekonwertowany na typ wbudowany. Wbudowany arg może być przekonwertowany na wskaźnik. Konwersja wskaźnika na typ wbudowany i na odwrót na ten sam typ wskaźnikowy dostarcza oryginalną wartość. Możliwe jest użycie do konwersji jeszcze nie zdefiniowanej klasy wskaźnika lub referencji. Wskaźnik na funkcje może być poprawnie przekonwertowany na wskaźnik na obiekt pod warunkiem, że dostarczany wskaźnik na obiekt, posiada wystarczającą ilość bitów do przechowania wskaźnika na funkcję. Wskaźnik na obiekt może być poprawnie przekonwertowany na wskaźnik na funkcję tylko jeśli wskaźnik na funkcję jest wystarczająco duży aby przechować wskaźnik na obiekt.
28
Modyfikacja danych w pliku binarnym
Algorytm: Ustawiamy się przed rekordem, który chcemy zmodyfikować za pomocą polecenia: plik1.seekp(sizeof(struct firmy)*(k-1)); Odczytujemy rekord (polecenie read), Ustawiamy poprawne dane, Zapisujemy rekord (polecenie write).
29
Usunięcie wybranego rekordu
Rozwiązanie z wykorzystaniem pomocniczego pliku: określamy, który rekord chcemy usunąć, niech będzie to rekord o numerze k, Przepisujemy wszystkie rekordy od numeru 0 do numeru k-1, Wczytujemy rekord o numerze k (nie przepisujemy go), Przepisujemy pozostałe rekordy o numerach k+1 do końca, Zamykamy pliki (mamy poprawne dane w tymczasowym i oryginalny zawiera wszystkie rekordy), Otwieramy oryginalny i czyścimy go (trunc), Przepisujemy wszystkie rekordy z pliku tymczasowego do oryginalnego, Usuwamy dane z tymczasowego.
30
Pliki jako parametry funkcji main
Nagłówek funkcji głównej: int main(int argc, char* argv[]); argc – liczba argumentów, argv[] – tablica argumentów. Przykładowy program: #include <fstream.h> int main(int argc, char* argv[]) { char znak; if(argc != 2) { cerr <<”Napisz: czytaj <nazwa-pliku>\n”; return 1; } ifstream plik=open(argv[1]); if(!plik) cerr <<”Nieudane otwarcie pliku do odczytu\n”; while(!plik.eof()) plik.get(znak); cout << znak; return 0;
Podobne prezentacje
© 2024 SlidePlayer.pl Inc.
All rights reserved.