Dane do programów wprowadzaliśmy do tej pory z klawiatury (lub generowaliśmy liczby losowe).
Wyniki obliczeń wypisywane były na ekranie komputera.
Duże ilości danych trudno jednak wpisywać ręcznie i w większości przypadków pobieramy je z plików zapisanych na dysku.
Podobnie jest z wynikami obliczeń – można je zapisać w postaci pliku i przeglądać w dowolnym momencie na ekranie komputera.
Dane do plików zapisujemy sekwencyjnie, to znaczy, że muszą być zapisywane po kolei.
Aby zapisać element setny należy najpierw zapisać 99 elementów.
Podobnie jest z odczytywaniem.
Plik należy otworzyć (do zapisu lub odczytu) OPEN
i po zakończeniu działań koniecznie go zamknąć CLOSE
.
Plik można otworzyć:
IFSTREAM
OFSTREAM
FSTREAM
WRITE
i strumieniem <<
.READ
i strumieniem >>
.EOF
pozwala sprawdzić czy ciągnięto już koniec pliku.Do obsługi konsoli służyła biblioteka iostream, do obsługi strumieni plikowych należy zadeklarować bibliotekę fstream.
#include <iostream> #include <fstream> using namespace std; int main() { ofstream ZAPIS("dane.txt"); int l=128; string t="Ala ma kota"; ZAPIS << "piszemy do pliku" << endl; ZAPIS << l << endl; ZAPIS << t << endl; string tekst; cout << "wpisz tekst:"; cin >> tekst; ZAPIS << tekst<< endl; ZAPIS.close(); return 0; }
W pliku dane.txt znajdują się 4 wiersze tekstów, które można odczytać zwykłym notatnikiem
piszemy do pliku 128 Ala ma kota cześć
ofstream - strumień o nazwie ZAPIS kojarzymy z plikiem ”dane.txt” na dysku w katalogu bieżącym.
Możemy zapisywać liczby i teksty, identycznie jak na ekranie konsoli za pomocą polecenia COUT.
Bezwzględnie należy pamiętać o zamknięciu strumienia plikowego za pomocą polecenia
close.
W pliku tekstowym "dane.txt" pojawią się 4 wiersze tekstu.
Problemem mogą być polskie znaki diakrytyczne, zapisywane przez Windows w kodzie OEM 852.
Podczas wczytywania tekstów z konsoli posługujemy się typem string, który reaguje standardowo na spację i enter.
Typu char należy używać raczej do wczytywania pojedynczych znaków.
Zapis do pliku (char): klawiatura-plik tekstowy
Do wczytywania znaków używamy funkcji getch() z biblioteki conio.h. Program będzie wczytywał znaki z klawiatury, zapisywał je do pliku dyskowego. Pętla zapisu kończy się w momencie naciśnięci klawisza ESC (kod 27).
ofstream klaw("klaw.txt"); char c; do { c=getch(); if (c==13) { cout << endl; klaw << endl; } if (c!=27){ cout << c; klaw << c; } } while (c!=27); klaw.close();
Zwróć uwagę, w jaki sposób program obsługuje klawisz ENTER - sami musimy zadbać o przejście do nowego wiersza i klawisz ESC - nie chcemy aby program wstawiał „dziwny” znaczek na końcu.
Zapis do pliku: liczby i kolumny
Pisanie liczb do pliku wygląda tak samo, jak pisaliśmy je na ekranie w konsoli.
#include <stdlib.h> ... ofstream Pliczby("liczby.txt"); int liczba; for (int i=0; i<10; i++) { liczba=rand() % 6 + 1; Pliczby << liczba << endl; cout << liczba << endl; } Pliczby.close();
W pliku liczby.txt znajdują się losowe liczby
6 6 5 5 6 5 1 1 5 3
Zapis w kolumnach - tabliczka mnożenia
ofstream plik("mnoz.txt"); int mnoz; for (int i=1; i<=10; i++) { for (int j=1; j<=10; j++) { mnoz=i*j; plik.width(4); cout.width(4); plik << mnoz; cout << mnoz; } plik << endl; cout << endl; } plik.close();
W pliku mnoz.txt znajdują się wyniki mnożenia, w takim samym układzie, jak na ekranie konsoli
Jeżeli znamy dokładnie ilość danych do odczytania, możemy np. korzystać z pętli FOR.
W wielu przypadkach jednak nie znamy długości pliku wówczas posługujemy się funkcją
eof() stosowaną w pętli while, co można przeczytać: „dopóki nie osiągnęliśmy końca pliku …”
ifstream PLIK("plik.txt"); while (!PLIK.eof()){ ... } PLIK.close();
Odczyt z pliku znak po znaku
Podczas czytania danych z plików pojawiają się problemy podobne do tych podczas zapisywania znaków – pomijane są spacja i enter (zarówno dla typu string i char).
ifstream ODCZYT("dane.txt"); char z; while (!ODCZYT.eof()){ ODCZYT >> z; cout << z; } ODCZYT.close();Przedstawiony fragment programu czyta pojedyncze znaki z pliku ”dane.txt” i wyświetla na ekranie, bez spacji i przejść do nowego wiersza.
Jeżeli użyjemy funkcji GET ominiemy problemy z tzw. "białymi znakami".
ODCZYT.get(z);
ifstream ODCZYT("dane.txt"); char z; while (!ODCZYT.eof()){ ODCZYT.get(z); cout << z; } ODCZYT.close();
Odczyt z pliku: czytanie wierszami
Instrukcja getline odczytuje całe wiersze, łączenie ze spacjami.
Jeśli odczytujemy w ten sposób liczby i teksty, konieczne będzie wyodrębnianie z tekstu fragmentów i konwersja.
ifstream Wodczyt("dane.txt"); string wiersz; while (!Wodczyt.eof()){ getline(Wodczyt,wiersz); cout << wiersz << endl; } Wodczyt.close();
Odczyt z pliku: liczby na ekran i liczby do tablicy
Liczby czytamy dokładnie tak samo jak teksty.
W pliku dane mogą być rozdzielone spacjami lub każda może wystąpić w nowym wierszu.
Spacja i nowy wiersz zostaną potraktowane identycznie - odczytane jako nowa watrość.
ifstream ODCZYT("liczby.txt"); int li; while (!ODCZYT.eof()){ ODCZYT >> li; cout << li; } ODCZYT.close();
int tabl[20]; int ile=0; ifstream oplik("liczby.txt"); if(oplik.is_open()) { while(!oplik.eof()) { oplik >> tabl[ile]; ile++; } } else cout << "Brak pliku"; oplik.close(); for (int i=0; i < ile; i++) cout << tabl[i];
Warto zwrócić uwagę na sprawdzenie poprawności otwarcia pliku.
Jeśli takiego pliku nie ma - funkcja is_open(), to możemy pominąć wykonywanie programu.
Problemy mogą pojawić się, jeśli plik na końcu zawiera pusty wiersz - do tablicy zostanie wczytany jeden więcej element - zero!
Do istniejącego pliku możemy dopisywać na końcu pliku nowe dane:
fstream dopis; dopis.open("dane.txt", ios::app); dopis << "Tekst dopisany na końcu"; dopis.close();
PALINDROMY
Palindromem nazywamy słowo, które czytane od lewej i od prawej strony
jest takie samo.
Palindromami są słowa: JABFDFBAJ, HAJAHAJAH, ABBA.
Słowo JANA nie jest palindromem.
zadanie:
Wygeneruj plik tekstowy palindrom.txt, który zawierał będzie 1000 słów o długościach od 2 do 25 znaków, każde w nowym wierszu, składających się z wielkich liter A, B, C, D, E, F, G, H, I, J.
Aby plik zawierał jakieś „ciekawe” palindromy zmodyfikuj program w następujący sposób:
- co 30 generowany wyraz sprawdź, czy jest krótszy niż 13 znaków
- jeśli tak, to doklej do niego ten sam odwrócony wyraz, np. DCEAB i doklejamy BAECD
ofstream PALzapisz("palindrom.txt"); for (int i=1; i <= 1000; i++){ int ile=rand() % 24 + 2; //ile znaków w wyrazie string pal=""; //sklejamy wyrazy z ile znaków for (int j=1; j <= ile; j++){ char zna=char(rand() % 10 +65); //losowe znaki o kodach 65-74 pal=pal+zna; } //co 30 wyraz i jeśli krótszy niż 13 znaków //robimy z wyrazu palindrom int dl=pal.length(); if (i%30 == 0 && dl <= 12){ for (int k=0; k < dl; k++) pal=pal+pal[dl-k-1]; } //zapisujemy wyrazy w pliku PALzapisz << pal << endl; cout << pal << endl; } PALzapisz.close();
Plik tekstowy palindrom.txt zawiera wygenerowane słowa (maksymalnie 1000).
Odczytaj je i sprawdź, które są palindromami.
Wynik wyświetl na ekranie oraz zapisz w pliku tekstowym palindrom-wynik.txt.
// odczytywanie pliku i sprawdzanie palindromów ifstream PALodczyt("palindrom.txt"); string wyraz; while (!PALodczyt.eof()){ PALodczyt >> wyraz; //całkowita połowa długości int dl=wyraz.length(); int dl2=dl/2; bool palindrom=true; //sprawdzamy od początku do połowy //i porównujemy ze znakami od końca for (int i=0; i < dl2; i++) //jeśli którakilwiek litera się nie zgadza //to nie jest palindrom if (wyraz[i] != wyraz[dl-1-i]) palindrom=false; if (palindrom) cout << wyraz << endl; } PALodczyt.close();
Przykładowe słowa będące palindromami z wygenerowanego pliku:
FBJGGJBF EE CBBC ICI ECGECFFCEGCE EIFBDHHDBFIE FF HGHAEFEIGIBBIGIEFEAHGH
HASŁA
Wygeneruj plik tekstowy hasla.txt, zawierający 200 słów, składających się z małych liter alfabetu angielskiego,
każde w osobnym wierszu, których długość wynosi od 3 do 10 znaków.
//generator pliku z hasłami //3-10 małych liter (ASCII 97-122) ofstream HASzapis("hasla.txt"); string napis; for (int i=1;i<=200;i++){ napis=""; int ile=rand() % 8 +3; //ile znaków od 3 do 10 for (int j=1;j<=ile;j++) //losujemy małe litery kodów ASCII napis+=rand() % (122-97+1)+97; HASzapis << napis << endl; } HASzapis.close();
Odpowiedz na poniższe pytania:
//parzysta-nieparzysta int PA=0; //parzyste int NP=0; //nieparzyste ifstream odczytA("hasla.txt"); string napisA; while (!odczytA.eof()){ odczytA >> napisA; //sprawdzamy długości napisów za pomocą modulo if (napisA.length() % 2 ==0) PA++; else NP++; } odczytA.close(); cout << " parzyste: " << PA << endl; cout << "nieparzyste: " << NP << endl;
//palindromy cout << "PALINDROMY" << endl; ifstream odczytB("hasla.txt"); string napisB; while (!odczytB.eof()){ odczytB >> napisB; int dl=napisB.length(); int dl2=dl/2; //na początku każdy wyraz jest palindromem bool palindrom=true; for (int i=0; i < dl-2; i++) //porównujemy znak z początku ze znakiem od końca if (napisB[i]!=napisB[dl-1-i]) //jeśli jakikolwiek znak różny to //nie jest palindromem palindrom=false; // jest palindromem, bo porównało //i wszystkie znaki były zgodne if (palindrom) cout << napisB << endl; } odczytB.close();
//dwa identyczne znaki cout << "ASCII 220"<< endl; ifstream odczytC("hasla.txt"); string napisC; while (!odczytC.eof()){ odczytC >> napisC; int dl=napisC.length(); //sprawdzamy do przedostatniego znaku //aby nie zawiesił się na ostatnim [i+1] for (int i=0;i < dl-2;i++) //dwa znaki obok siebie takie same if (napisC[i] == napisC[i+1]) { cout << napisC << endl; break; } } odczytC.close();
CIĄGI
Wygeneruj plik tekstowy ciagi.txt, zawierający 1000 słów składających się z trzech liter A, B, C, każde słowo w osobnym wierszu, litery mogą się powtarzać.
ofstream CIAGzapis("ciagi.txt"); string napis; for (int i=1; i<=1000; i++){ napis=""; //losowe znali ABC napis=rand() % 3+65; napis+=rand() % 3+65; napis+=rand() % 3+65; CIAGzapis << napis << endl; } CIAGzapis.close();
Odpowiedz na poniższe pytania:
ifstream CIAGodczyt("ciagi.txt"); int licznik = 0; string napis; while (!CIAGodczyt.eof()) { CIAGodczyt >> napis; //sprawdzamy zerowy z pierwszym i zerowy z drugim //nie potrzeba sprawdzać pierwszego z drugim if (napis[0]==napis[1] && napis[0]==napis[2]) licznik++; } CIAGodczyt.close();
ifstream CIAGodczyt("ciagi.txt"); int licznik = 0; string napis; while (!CIAGodczyt.eof()) { CIAGodczyt >> napis; //wystarczy sprawdzić zerowy z drugim if (napis[0]==napis[2]) licznik++; } CIAGodczyt.close();
CYFRY
Wygeneruj plik tekstowy cyfry.txt, zawierający 1000 liczb naturalnych, mniejszych niż 10000, każda w osobnym wierszu.
ofstream CYFRYzapis("cyfry.txt"); for (int i=1; i <= 1000; i++){ int c=rand() % 10000 + 1; CYFRYzapis << c; //nowy wiersz bez ostatniego if (i < 1000) CYFRYzapis << endl; } CYFRYzapis.close();
Odpowiedz na poniższe pytania:
ifstream CYFRYodczytA("cyfry.txt"); int liczba, suma=0, ilosc=0; while (!CYFRYodczytA.eof()){ CYFRYodczytA >> liczba; ilosc++; suma += liczba; } CYFRYodczytA.close(); //aby wynik był rzecywisty, wykonujemy daiałanie: (ilosc*1.0) cout << "Średnia=" << suma/(ilosc*1.0) << endl;
ifstream CYFRYodczytB("cyfry.txt"); int liczbaB; int CP=0;//licznik parzystych int CN=0;//i nieparzystych while (!CYFRYodczytB.eof()){ CYFRYodczytB >> liczbaB; if (liczbaB % 2 == 0) CP++; else CN++; } CYFRYodczytB.close(); cout << "Parzyste=" << CP << endl; cout << "nieParzyste=" << CN << endl;
DWÓJKOWE
Wygeneruj plik tekstowy napisy.txt, zawierający 1000 napisów od 20 do 100 znaków.
Napisy to liczby binarne składające się ze znaków ‘0’ lub ‘1’.
ofstream NDzapis("liczby.txt"); int ile; int znak; string napis; for (int j=1;j<=1000;j++){ ile=rand() %80 + 20; //20-100 if(rand()%150 == 10) napis = "00000000000"; else if(rand()%200 == 10) napis = "1111111111111111111111111111"; else if(rand()%200 == 10) napis = "00000000000000000000000000000000000000000010000000000000100000000000000000000100"; else { napis=""; for (int i=1;i<=ile;i++){ znak=rand() % 2;//0 lub 1 losowo //znak ASCII '0' lub '1' napis=napis+char(znak+48); } } NDzapis << napis << endl; } NDzapis.close();
W pliku napisy.txt znajduje się 1000 napisów o długościach od 2 do 16 znaków, każdy napis w osobnym wierszu. W każdym napisie mogą wystąpić jedynie dwa znaki: „0” lub „1”. Odpowiedz na poniższe pytania: ekran i plik
int zadanie1() { int parzyste=0; string liczba; ifstream plik("liczby.txt"); if(plik.is_open()) { while(!plik.eof()) { plik >> liczba; if(liczba.size() % 2 == 0) parzyste++; } plik.close(); } else { cout << "Problem z otwarciem pliku ilczby.txt "; } return parzyste; }
int zadanie2() { int zera=0, jedynki=0, ilosc=0; string liczba; ifstream plik("liczby.txt"); if(plik.is_open()) { while(!plik.eof()) { zera=0; jedynki=0; plik >> liczba; for(int i=0; i<liczba.size(); i++) { if(liczba[i] == '0') zera++; if(liczba[i] == '1') jedynki++; } if(zera == jedynki) ilosc++; } plik.close(); } else { cout << "Problem z otwarciem pliku ilczby.txt "; } return ilosc; }
void zadanie3() { int zera=0, jedynki=0, suma=0; string liczba; ifstream plik("liczby.txt"); if(plik.is_open()) { while(!plik.eof()) { suma = 0; plik >> liczba; for(int i=0; i<liczba.size(); i++) { suma += int(liczba[i]) - 48; } if(suma == 0) zera++; if(suma == liczba.size()) jedynki++; } plik.close(); cout << "W pliku liczby.txt:\n" << zera << " - same zera\n" << jedynki << " - same jedynki."; } else { cout << "Problem z otwarciem pliku ilczby.txt "; } }
void zadanie4() { int tablica[80]; for (int i=0; i < 80; i++) tablica[i]=0; string liczba; ifstream plik("liczby.txt"); if(plik.is_open()) { while(!plik.eof()) { plik >> liczba; tablica[liczba.size()-20]++; } plik.close(); cout << "W pliku liczby.txt:\n"; for(int i=0; i < 80; i++) { cout << i+20 << " znakow: " << tablica[i] << ", "; } } else { cout << "Problem z otwarciem pliku ilczby.txt "; } }
int jedynki(string liczba) { int ilosc=0; for(int i=0; i<liczba.length(); i++) { if(liczba[i] == '1') ilosc++; } return ilosc; } void zadanie5() { int ile=0, ile1, max1=0; string liczba; ifstream plik("liczby.txt"); if(plik.is_open()) { plik >> liczba; ile = 1; max1 = ile1 = jedynki(liczba); while(!plik.eof()) { plik >> liczba; ile0 = jedynki(liczba); if(ile1 == max1) ile++; else if(ile1 > max1) { max1 = ile1; ile = 1; } } plik.close(); cout << "W pliku liczby.txt maksymalna ilosc jedynek wynosi: " << max1 << " - takich liczb jest: " << ile; } else { cout << "Problem z otwarciem pliku ilczby.txt "; } }
int zera(string liczba) { int ilosc=0; for(int i=0; i<liczba.length(); i++) { if(liczba[i] == '0') ilosc++; } return ilosc; } void zadanie6() { int ile=0, ile0, max0=0; string liczba; ifstream plik("liczby.txt"); if(plik.is_open()) { plik >> liczba; ile = 1; max0 = ile0 = zera(liczba); while(!plik.eof()) { plik >> liczba; ile0 = zera(liczba); if(ile0 == max0) ile++; else if(ile0 > max0) { max0 = ile0; ile = 1; } } plik.close(); cout << "W pliku liczby.txt maksymalna ilosc zer wynosi: " << max0 << " - takich liczb jest: " << ile; } else { cout << "Problem z otwarciem pliku ilczby.txt "; } }