S t r o n a
| 1 WETI Politechnika Gdańska, POP v.1.4.4
Laboratorium 8. Pliki
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
| 2 WETI Politechnika Gdańska, POP v.1.4.4
Pytania
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
| 3 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
| 4 WETI Politechnika Gdańska, POP v.1.4.4
Odpowiedzi
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
| 5 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, ios::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
| 6 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
| 7 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
| 8 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.