петак, 06. новембар 2015.

Rad sa tekstualnim i binarnim datotekama u C++ programskom jeziku


Najvažnija stvar svake aplikacije je da negde čuva informacije i da koristi iste po potrebi. Inače rezultati vaše aplikacije bi trajali samo dok radi program; čim bi ste ga pokrenuli ponovo, ne bi ste mogli videti informacije koje ste pre unosili. Čak i najbanalnija igrica mora negde da pamti rezultate igrača, međutim RAM memorija nije postojana i ona traje dok se računar ne ugasi. Zato se podaci čuvaju u nekom fajlu ili u bazi podataka. Kad C++ programeri pričaju o tokovima ili drugačije rečeno; streams – strimovima; to znači da pričaju o nečemu gde mogu da se učitaju ili upisuju podaci. Strimovi u suštini obezbeđuju jednostavan rad i sa unosom i sa čitanjem podataka u tekstualni ili binarni fajl. Prvo je potrebno da omogućite podršku operacijama fajl tokova direktivom #include <fstream> koja vam omogućava korišćenje objekata ifstrem i ofstream koji regulišu otvaranje i zatvaranje datoteka.

 

( Input and Output Stream )
 

Zahvaljujući <fstream> koji inače uključuje iostream objekte koji održavaju flagove i obaveštavaju o stanju ulaza i izlaza, vama je omogućeno da koristite logičke funkcije poput eof(), bad(), fail() ili good() i sa takvim funkcijama rad sa bilo kojim tekstualnim fajlom je jednostavan.

Kako da upisujem i učitavam podatke u tekstualnu datoteku?


Najlakše će vam se to samo objasniti kodiranjem. Pogledajte kod programa koji bi se mogao koristit za pravljenje telefonskog imenika; phonebook koji upisuje i čita podatke iz tekstualne datoteke phonebook.dat. Postoji više načina i mogućnosti na koji način možete unositi i čitati podatke i pored toga što će te uvek koristiti <fstream>. Npr. možete umetnuti zareze, između vaših podataka ili svakom podatku odrediti maksimalnu dužinu, pa na osnovu toga manipulisati sa podacima. Radi lakšeg razumevanja, ovaj kod prikazuje samo najjednostavniji način upisa i čitanja podataka iz tekstualnog fajla, i u njega nisu uključene stvari poput traženja određenog klijenta i telefona, brisanje klijenta, editovanje i prepravljanje klijenta. Takve stvari bi ste najlakše isprogramirali što bi ste sve podatke prvo prebacili u nizove iz tekstualnog fajla i onda bi ste podatke u nizovima sortirali, brisali, analizirali, pretraživali i ostalo. Na taj način to je mnogo jednostavnije nego da direktno manipulišete sa podacima iz tekst fajlova. Ali naravno sve je to stvar vašeg izbora.

#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

bool goodChoice = true;
char choice = '/0';
void PrintMenu();
void AddContact();
void ListContacts();

struct Person
{
       string name = "";
       string phone = "";
};

int main()
{
    PrintMenu();

       while (goodChoice != false)
       {
             switch (choice)
             {
             case 'a':
             case 'A':
                    AddContact();
                    break;

             case 'l':
             case 'L':
                    ListContacts();
                    break;

           case 'q':
             case 'Q':
                    goodChoice = false;
                    break;

             default:
                    PrintMenu();
                    break;
             }
       }

       system("PAUSE");
    return 0;

}

void PrintMenu()
{
       system("CLS");
      
       cout << endl << "\t               PHONEBOOK" << endl << endl;
       cout << endl << "\t-------------- Main Menu --------------";
       cout << endl << "\t|                                     |";
       cout << endl << "\t|              (A)dd contact          |";
       cout << endl << "\t|              (L)ist contacts        |";
       cout << endl << "\t|              (Q)uite                |";
       cout << endl << "\t|                                     |";
       cout << endl << "\t---------------------------------------";

       cout << endl << endl << "Your choice: ";
       cin >> choice;

}

void AddContact()
{
       char save = '/0';
       Person person;
       system("CLS");

       cin.ignore();

       cout << "Enter your full name: ";
       getline(std::cin,person.name);
      
       cout << "Enter the phone number: ";
       getline(std::cin,person.phone);

       cout << endl << "Save Contact ( Y - yes)? ";
       cin >> save;

       if (save == 'Y' || save == 'y')
       {
             try
             {
                    ofstream dataFile;
                    dataFile.open("Phonebook.dat", ios::app);
                   
                    dataFile << person.name << endl;
                    dataFile << person.phone << endl;
                    dataFile.close();

                    cout << endl << "Contact saved." << endl << endl;
                    system("PAUSE");

                    PrintMenu();

             }
             catch (exception ex)
             {
                    cout << endl << "Error save data to the file!" << endl;
                    system("PAUSE");
             }
       }
       else
       {
             PrintMenu();
       }
      
}

void ListContacts()
{
              system("CLS");
      
                    ifstream dataFile;
                    dataFile.open("Phonebook.dat");

                    if (dataFile.fail())
                    {
                           cerr << "Error read data!" << endl << endl;
                           system("PAUSE");
                           PrintMenu();
                           return;

                    }
                   
                    string outLine = "";
                    short i = 0;
                    while (!dataFile.eof())
                    {
                           ++i;
                           getline(dataFile, outLine);
                           cout << outLine << endl;
                       
                           if (i % 2 == 0) cout << endl;
                    }
                                       
                    dataFile.close();

                    cout << endl;
                    system("PAUSE");

                    PrintMenu();

}

Obratite pažnju na upis podataka u tekstualni fajl. Ova linija koda:

 dataFile.open("Phonebook.dat", ios::app);

ima argument app koji dodaje podatke posle upisanih podataka u tekstualnu datoteku. Inače ako bi ste argument izostavili ili umesto argumenta app koristili out, onda bi ste uvek u datoteci imali zapisan samo zadnjeg klijenta. Ova naredba ukoliko nema tekstualnu datoteku, sama kreira datoteku. Za to je mogućnost velika kad su u pitanju greške. Zato za zapisivanje podataka uvek treba koristiti try catch iskaz dok za čitanje podataka je dovoljno koristiti if uslovni iskaz sa funkcijom fail(). Kad pokrenete navedeni program, unesete imena i brojeve telefona vaši podaci će biti sačuvani:

Manuel Radovanovic
012 345 6789

Bill Gates
987 6543 210

Press any key to continue . . .


Kako navedeni program funkcioniše možete pogledati i na video-u:



( C++ Tutorial - 21. Writing and Reading Data to Text Files )

Kako da upisujem i učitavam podatke u binarnu datoteku?

Neki operativni sistemi poput DOS-a razlikuju binarne i tekstualne datoteke. Problem kod tekstualnih datoteka je što i velike brojeve smeštaju kao tekst, stringove numerike što nije efikasno. Tako svaki broj veći od milion zauzima više od 7 pojedinačnih karaktera. Za binarne fajlove; C++ obezbeđuje ios::binary flag, međutim neki operativni sistemi ga ignorišu jer je u njima je sve binarni fajl dok u nekim sistemima binarni fajl je nelegalan i neće preći kompilaciju. Kao što možda očekujete, binarni fajlovi mogu da čuvaju i integer i string i sve strukture podataka. Pogledajte sledeći program i analizirajte kod.

#include "stdafx.h"
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

bool goodChoice = true;
char choice = '/0';
void PrintMenu();
void AddAddress();
void ListAddresses();

struct Person
{
       char name[30];
       char address[50];
       char zip[10];
       char city[20];
       char state[30];

};

int main()
{
       PrintMenu();

       while (goodChoice != false)
       {
             switch (choice)
             {
             case 'a':
             case 'A':
                    AddAddress();
                    break;

             case 'l':
             case 'L':
                    ListAddresses();
                    break;

             case 'q':
             case 'Q':
                    goodChoice = false;
                    break;

             default:
                    PrintMenu();
                    break;
             }
       }

       system("PAUSE");
       return 0;

}

void PrintMenu()
{
       system("CLS");

       cout << endl << "\t             ADDRESS BOOK" << endl << endl;
       cout << endl << "\t-------------- Main Menu --------------";
       cout << endl << "\t|                                     |";
       cout << endl << "\t|              (A)dd address          |";
       cout << endl << "\t|              (L)ist addresses       |";
       cout << endl << "\t|              (Q)uite                |";
       cout << endl << "\t|                                     |";
       cout << endl << "\t---------------------------------------";

       cout << endl << endl << "Your choice: ";
       cin >> choice;

}

void AddAddress()
{
       char save = '/0';
       Person person;

       system("CLS");

       cin.ignore();

       cout << "Enter your full name: ";
       cin.getline(person.name, sizeof(person.name) - 1);

       cout << "Enter the street address: ";
       cin.getline(person.address, sizeof(person.address) - 1);

       cout << "Enter the ZIP: ";
       cin.getline(person.zip, sizeof(person.zip) - 1);

       cout << "Enter the city: ";
       cin.getline(person.city, sizeof(person.city) - 1);

       cout << "Enter the state: ";
       cin.getline(person.state, sizeof(person.state) - 1);

       cout << endl << "Save Addreess ( Y - yes)? ";
       cin >> save;

       if (save == 'Y' || save == 'y')
       {
             try
             {
                    ofstream dataFile;
                    dataFile.open("AddressBook.dat", ios::app | ios::binary);

                    dataFile.write(person.name, sizeof(person.name));
                    dataFile.write(person.address, sizeof(person.address));
                    dataFile.write(person.zip, sizeof(person.zip));
                    dataFile.write(person.city, sizeof(person.city));
                    dataFile.write(person.state, sizeof(person.state));

                    dataFile.close();

                    cout << endl << "Address saved." << endl << endl;
                    system("PAUSE");

                    PrintMenu();

             }
             catch (exception ex)
             {
                    cout << endl << "Error save data to the file!" << endl;
                    system("PAUSE");
             }
       }
       else
       {
             PrintMenu();
       }

}

void ListAddresses()
{
       Person person;

       system("CLS");

       try
       {
             int size = 0;
             ifstream dataFile;
             dataFile.open("AddressBook.dat", ios::in | ios::binary);

             dataFile.seekg(0, ios::end);
             size = (int)dataFile.tellg();
             dataFile.seekg(0, ios::beg);
             while (dataFile.tellg() < size)
             {
                    dataFile.read((char*)person.name, sizeof(person.name));
                    dataFile.read((char*)person.address, sizeof(person.address));
                    dataFile.read((char*)person.zip, sizeof(person.zip));
                    dataFile.read((char*)person.city, sizeof(person.city));
                    dataFile.read((char*)person.state, sizeof(person.state));

                    cout << person.name << endl;
                    cout << person.address << endl;
                    cout << person.zip << endl;
                    cout << person.city << endl;
                    cout << person.state << endl << endl;
             }
                          
             dataFile.close();
       }
       catch (exception ex)
       {
             cerr << "Error read data!" << endl << endl;
       }

       cout << endl;
       system("PAUSE");

       PrintMenu();

}

Kao što vidite čitanje binarnih fajlova je malo komplikovanije jer ne možete samo reći petlji while da čita fajl do kraja. Kad pokrenete program i unesete adrese, vaši podaci će biti sačuvani u binarnom fajlu.

Manuel Radovanovic
Street One
11000
Belgrade
Serbia, EU

Bill Gates
500 Fifth Avenue North
98109
Seattle
WA, USA

Press any key to continue . . .


Kako program funkcioniše možete pogledati i na video-u:


( C++ Tutorial - 22. Writing and Reading Data to Binary Files )