Przed zajęciami laboratoryjnymi zapoznaj się z następującymi pozycjami literatury:
1. Wykład z przedmiotu „Podstawy programowania”
2. J. Grębosz „Symfonia C++” tom 1. ,Oficyna Kallimach, Kraków, 1999
Rozdziały: 21.12, 21.13, 21.14, 21.15, 21.16, 21.17
Przygotowując się do laboratorium przeanalizuj podane poniżej przykłady, odpowiedz na pytania, rozwiąż testy i napisz odpowiednie programy. Po zajęciach zrób zadania podane w ostatnim punkcie tego opracowania.
Przykłady i pytania
1. Otwieranie i zamykanie plików
Przykład L8_F0_P1 i L8_F0_P2 Przeanalizuj programy i odpowiedz na pytania
//L8_F0_P1.cpp
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ifstream plik("L8_F0_P1.txt"); //otwarcie pliku o nazwie "L8_F0_P1.txt"
if(!plik) { //sprawdzenie, czy plik został otwarty
cout << "Plik nie zostal otwarty\n";
return 1;
}
int liczba;
plik >> liczba; //wczytanie liczby z pliku
cout << liczba << endl;
plik.close(); //zamknięcie pliku
return 0;
}
//L8_F0_P2.cpp
#include <iostream>
#include <fstream>
using namespace std;
int main() {
fstream plik("L8_F0_P1.txt", ios::in); //otwarcie pliku o nazwie "L8_F0_P1.txt"
if(!plik) { //sprawdzenie, czy plik został otwarty
cout << "Plik nie zostal otwarty\n";
return 1;
}
int liczba;
plik >> liczba; //wczytanie liczby z pliku
cout << liczba << endl;
plik.close(); //zamknięcie pliku
return 0;
}
Plik L8_F0_P1.txt
463 859 203 20
S t r o n a | 1 WETI Politechnika Gdańska, POP v.1.4.4
Sprawdź, czy dla podanych poniżej danych program działa z zgodnie z twoimi przewidywaniami:
a) Co wypiszą programy jeśli zabraknie pliku L8_F0_P1.txt?
b) Co wypisze na ekranie program L8_F0_P1? Co wypisze na ekranie program L8_F0_P2?
c) Czym różni się klasa ifstream od fstream? Czy w programach L8_F0_P1 i L8_F0_P2 widoczna jest ta różnica?
d) Odpowiedz co oznaczają flagi otwarcia pliku:
• ios:: in
• ios:: out
• ios:: in | ios:: out
Jaki jest domyślny tryb otwarcia pliku w klasie fstream.
Odpowiedzi
a) Wypisze: Plik nie zostal otwarty
b) Wypiszą to samo: 463
c) Klasa ifstream służy wyłącznie do odczytu, natomiast klasa fstream służy do odczytu lub zapisu w zależności od trybu otwarcia pliku. W tych programach nie widać różnicy.
d) Flaga ios:: in – plik tylko do odczytu
Flaga ios:: out – plik tylko do zapisu
Flaga ios:: in | ios:: out – plik do zapisu i do odczytu
W klasie fstream domyślną flagą jest ios:: in| ios:: out.
2. Przetwarzanie całego pliku
Przykład L8_F0_P3 Przeanalizuj program i odpowiedz na pytania
//L8_F0_P3.cpp
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ifstream plik("L8_F0_P1.txt");
if(!plik) {
cout << "Plik nie zostal otwarty\n";
return 1;
}
int liczba;
while(plik >> liczba) { //wczytanie liczb z pliku
cout << liczba << endl;
}
plik.close(); //zamknięcie pliku
return 0;
}
Pytania
a) Ile liczb wypisze powyższy program?
b) Wyrażenie plik>> liczba przyjmuje wartość boolowską. Kiedy przyjmuje wartość true, a kiedy false?
S t r o n a | 2 WETI Politechnika Gdańska, POP v.1.4.4
c) Zmodyfikuj plik L8_F0_P1.txt tak, aby zawierał 463 859A203 20(zamiana spacji pomiędzy 859 i 203 na literę A). Co teraz wyświetli powyższy program i dlaczego?
Odpowiedzi
a) Program wypisze 4 liczby.
b) Przyjmuje wartość true, gdy program poprawnie odczytał liczbę. Przyjmuje wartość false, gdy program nie mógł kolejno odczytywanych znaków zinterpretować jako wartości liczby lub gdy
skończy się plik lub wystąpił błąd.
c) Program wypisze wartości 463 oraz 859. Dalej nie będzie wypisywał, bo litera A nie może być częścią liczby, więc plik>> liczba zwróci false.
Przykład L8_F0_P4 Przeanalizuj program i odpowiedz na pytania
//L8_F0_P4.cpp
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
int main() {
ifstream plik("L8_F0_P4a.dat", ios::binary);
if(!plik) {
cout << "Plik nie zostal otwarty\n";
return 1;
}
unsigned char txt[16];
while(plik) {
plik.read(reinterpret_cast<char*>(txt), 16);
int len = plik.gcount();
if(len==0) break;
for(int i=0; i<len; i++) {
cout << setfill('0') << setw(2) << hex << static_cast<int>(txt[i]) << " ";
}
//$$$
//$$$
cout << "| ";
for(int i=0; i<len; i++) {
if(txt[i]=='\n' || txt[i]=='\r' || txt[i]=='\t' || txt[i]=='\b' || txt[i]=='\a')
cout << '.';
else
cout << txt[i];
}
//$$$
//$$$
cout << " |" << endl;
}
plik.close();
return 0;
}
Pytania
Przeanalizuj a następnie uruchom powyższy program i odpowiedz na pytania
a) Co program wypisuje na standardowym wyjściu?
b) Do czego służy funkcja read?
c) Co zwraca funkcja gcount?
d) Co oznaczają znaki '\n', '\r', '\t', '\b', '\a'?
e) Zmień miejsca w programie oznaczone $$$ tak, aby dla plików o rozmiarze niepodzielnym przez 16
(np. L8_F0_P4b.txt) program wypisywał spacje dopełniające do 16 znaków.
S t r o n a | 3 WETI Politechnika Gdańska, POP v.1.4.4
a) Wypisuje zawartość pliku, heksadecymalnie po 16 bajtów na linię.
b) Funkcja read wczytuje podaną liczbę bajtów z pliku do tablicy znaków.
c) Funkcja gcount zwraca liczbę bajtów wczytanych przez funkcję read.
d) '\n' – nowa linia (sprawdź: cout << " Ala ma\ nkota.";)
'\r' – przejście do początku bieżącej linii (sprawdź: cout << " Ala ma\ rkota.";)
'\t' – znak tabulacji (sprawdź: cout << " Ala ma\ tkota.";)
'\b' – kasowanie poprzedzającego znaku (sprawdź: cout << " Ala ma\ bkota.";)
'\a' – sygnał dźwiękowy; może nie działać (sprawdź: cout << " Ala ma\ akota.";) e) Należy zmienić pierwsze dwa $$$ na
for(int i=len; i<16; i++)
cout << setfill(' ') << setw(3) << " ";
Należy zmienić następne dwa $$$ na
for(int i=len; i<16; i++)
cout << ' ';
3. Zapisywanie danych do pliku
Przykład L8_F0_P5 Przeanalizuj program i odpowiedz na pytania. Po zakończeniu programu sprawdź
zawartość pliku L8_F0_P5.txt.
Uwaga: Aby zakończyć wczytywanie tekstu w nowej linii wpisz Ctrl+ Z i potwierdź klawiszem Enter.
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ofstream plik("L8_F0_P5.txt");
if(!plik) {
cout << "Plik nie zostal otwarty\n";
return 1;
}
string tekst;
cout << "Wpisz tekst: ";
while(cin >> tekst)
plik << tekst << "\n";
plik.close();
return 0;
}
Pytania
a) Dlaczego za każdym razem plik L8_F0_P5.txt jest czyszczony i dane są zapisywane na nowo?
b) Jak zmodyfikować program, żeby dodawał tekst na koniec pliku (nie kasował poprzednich danych)?
c) Zauważ, że program wczytuje pojedyncze słowa zapisując je w osobnych liniach. Zmień program tak, aby zapisywał tekst liniami.
d) Zmień program tak, aby po zakończonym wczytywaniu wypisywał wszystkie dane na ekran.
S t r o n a | 4 WETI Politechnika Gdańska, POP v.1.4.4
Odpowiedzi
a) Obiekt ofstream standardowo podczas otwierania pliku kasuje jego dane, bo jego domyślny tryb otwarcia to ios:: out| ios:: trunc. Flaga trunc powoduje takie zachowanie obiektu.
b) Należy zamienić linię z ofstream plik(" L8_F0_P5.txt"); na ofstream plik(" L8_F0_P5.txt", ios:: app); albo ofstream plik(" L8_F0_P5.txt", ios:: ate); albo fstream plik(" L8_F0_P5.txt", ios:: out | ios:: app); albo fstream plik(" L8_F0_P5.txt", ios:: out | ios:: ate); Można także otworzyć plik do odczytu i zapisu ( ios:: out | ios:: in) i ustawić wskaźnik pliku na jego koniec ( plik.seekp( 0, io s:: end) ).
c) Przykład rozwiązania
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ofstream plik("L8_F0_P5.txt");
if(!plik) {
cout << "Plik nie zostal otwarty\n";
return 1;
}
string tekst;
cout << "Wpisz tekst:\n";
while(cin) {
getline(cin, tekst);
plik << tekst << "\n";
}
plik.close();
return 0;
}
d) Przykład rozwiązania
#include <iostream>
#include <fstream>
using namespace std;
int main() {
fstream plik("L8_F0_P5.txt", ios::in|ios::out|ios::trunc);
if(!plik) {
cout << "Plik nie zostal otwarty\n";
return 1;
}
string tekst;
cout << "Wpisz tekst:\n";
while(cin) {
getline(cin, tekst);
plik << tekst << "\n";
}
plik.seekg(0);
while(plik) {
getline(plik, tekst);
cout << tekst << "\n";
}
plik.close();
return 0;
}
S t r o n a | 5 WETI Politechnika Gdańska, POP v.1.4.4
Testy
1. Podaj jakie flagi można stosować przy otwieraniu pliku. Które flagi wykluczają się?
2. Jaką flagę należy ustawić, aby otwierany plik można było odczytywać i zapisywać?
3. Co zwraca funkcja tellg?
Odpowiedzi
Test 1: Flagi: ios:: out, ios:: in, ios:: app, ios:: ate, ios:: binary, ios:: trunc.
Tryby wykluczające to ios:: trunc i ios:: app.
Test 2: ios:: in| ios:: out
Test 3: Funkcja tellg zwraca pozycję wskaźnika pobierania pliku.
Zadania przygotowujące do laboratorium
Zapoznaj się z treścią zadania, przemyśl rozwiązanie a następnie napisz, uruchom i przetestuj programy. Nie wczytuj od razu całego pliku do tablic ani do bardzo długich zmiennych typu napisowego.
Zadanie L8_F0_Z1
Napisz program, który wczytuje binarnie liczby z pliku o nazwie L8_F0_Z1a.dat i zapisuje do pliku L8_F0_Z1b.dat te same liczby w odwrotnym porządku.
//L8_F0_Z1.cpp
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ifstream plikIn("L8_F0_Z1a.dat", ios::binary);
if(!plikIn) {
cout << "Plik wejsciowy nie otwarty\n";
return 0;
}
ofstream plikOut("L8_F0_Z1b.dat", ios::binary);
if(!plikOut) {
cout << "Plik wyjsciowy nie otwarty\n";
return 0;
}
int liczba;
plikIn.seekg(0, ios::end) ; // przejdź na koniec pliku
int lenPlik = plikIn.tellg(); // sprawdź wielkość pliku
// wartość lenPlik powinna być wielokrotnością sizeof(int)
lenPlik /= sizeof(int); // ilość liczb w pliku
while(lenPlik>0) {
lenPlik--;
plikIn.seekg(lenPlik*sizeof(int), ios::beg);
plikIn.read( reinterpret_cast<char*>(&liczba), sizeof(int) );
plikOut.write( reinterpret_cast<char*>(&liczba), sizeof(int) ); // zapisz liczbę do drugiego pliku
}
plikOut.close();
plikIn.close();
return 0;
}
S t r o n a | 6 WETI Politechnika Gdańska, POP v.1.4.4
Zadanie L8_F0_Z2
Napisz program, który podwaja każdą liczbę z pliku L8_F1_Z2.dat. Liczby w tym pliku są zapisane binarnie.
//L8_F0_Z2.cpp
#include <iostream>
#include <fstream>
using namespace std;
int main() {
fstream plik("L8_F0_Z2.dat", ios::binary|ios::in|ios::out);
if(!plik) {
cout << "Plik nie otwarty\n";
return 0;
}
plik.seekg(0, ios::end); // sprawdzenie długości pliku
int lenPlik = plik.tellg()/sizeof(int); //liczba liczb w pliku
int liczba;
for(int i=0; i<lenPlik; i++) {
plik.seekg(i*sizeof(int), ios::beg);
plik.read( reinterpret_cast<char*>(&liczba), sizeof(int) );
liczba = 2*liczba;
plik.seekp(i*sizeof(int), ios::beg); //ustawiamy głowicę w to samo miejsce
plik.write( reinterpret_cast<char*>(&liczba), sizeof(int) ); //wpisujemy liczbę
}
plik.close();
return 0;
}
Zadanie L8_F0_Z3
Wczytaj plik L8_F0_Z3.txt i policz liczbę wystąpień liter 'a' - 'z' i 'A' - 'Z' oraz cyfr '0' - '9'.
//L8_F0_Z3.cpp
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ifstream plik("L8_F0_Z3.txt");
if(!plik) {
cout << "Plik wejsciowy nie otwarty\n";
return 0;
}
int cntTab[128];
for(int i=0; i<128; i++)
cntTab[i] = 0;
char znak;
while(plik>>znak) {
if(0<=znak && znak<128)
cntTab[static_cast<int>(znak)]++;
}
plik.close();
for(int i='a'; i<='z'; i++)
cout << "Litera " << static_cast<char>(i)
<< " wystepowala " << cntTab[i] << "raz(y)\n";
for(int i='A'; i<='Z'; i++)
cout << "Litera " << static_cast<char>(i)
<< " wystepowala " << cntTab[i] << "raz(y)\n";
for(int i='0'; i<='9'; i++)
cout << "Liczba " << static_cast<char>(i)
<< " wystepowala " << cntTab[i] << "raz(y)\n";
return 0;
}
S t r o n a | 7 WETI Politechnika Gdańska, POP v.1.4.4
Zadania do samodzielnego rozwiązania po laboratorium
Zapoznaj się z treścią zadania, przemyśl rozwiązanie a następnie napisz, uruchom i przetestuj programy. Nie wczytuj od razu całego pliku do tablic ani do bardzo długich zmiennych typu napisowego.
L8_F3_Z1
Napisz program, który odwraca kolejność zapisanych liczb w pliku L8_F3_Z1.txt. Program nie może używać dodatkowych plików. Liczby w pliku są zapisane binarnie.
L8_F3_Z2
W plikach L8_F3_Z2a.txt oraz L8_F3_Z2b.txt znajdują się posortowane liczby. Napisz program, który wypisuje tylko te liczby, które występują w obu plikach. Można założyć, że liczby w ramach jednego pliku są różne.
L8_F3_Z3
W plikach L8_F3_Z3a.txt oraz L8_F3_Z3b.txt znajdują się posortowane liczby. Napisz program, który scali te pliki tak, aby w wynikowym pliku L8_F3_Z3c.txt znalazły się wszystkie liczby ułożone od najmniejszej do największej liczby.
L8_F3_Z4
Policz wszystkie wystąpienia frazy 'abb' w pliku L8_F3_Z4.txt.
L8_F3_Z5
Napisz program łączący pliki L8_F3_Z5a.jpg i L8_F3_Z5b.jpg w taki sposób, że wykonujemy operację xor na kolejnych bajtach obu plików. Łącząc w ten sposób każdy n-ty bajt pierwszego pliku i n-ty bajt drugiego pliku otrzymamy zdjęcie zapisane w formacie jpg.
S t r o n a | 8 WETI Politechnika Gdańska, POP v.1.4.4