Friday, August 28, 2015

Chapter 13 - Files and Templates

 

LET’S LEARN

FILES IN C++

    INPUT/OUTPUT OPERATIONS WITH FILES

    OPENING A FILE

    CLOSING A FILE

    FILE INPUT FUNCTIONS

          Reading of Character Data, End Of File, Reading of Numeric Data

    FILE OUTPUT FUNCTIONS

           Writing of Character Data, Writing of Numeric Data

    READING & WRITING A SET OF CHARACTERS

           read(), write()

    Checking STREAM-STATE Flags

            bad(), fail(), eof(), good(), clear()

    INTERNAL STREAM POINTERS : get, put

    MANIPULATION OF INTERNAL STREAM POINTERS

             tellg(), tellp(), seekg(), seekp()

    READING & WRITING A CLASS OBJECT

              read(), write()

TEMPLATES IN C++

     Function Templates

     Applying Function Templates


FILES IN C++

A computer file in C++ is a permanent resource for storing information as data units. Once a file is created by a program, it can be accessed by other independent programs for processing and reports generation.

INPUT/OUTPUT OPERATIONS WITH FILES

C++ provides the following classes to perform input and output of characters to/from files:

ofstream  : Stream class to write onto files (output file)

ifstream   : Stream class to read from files (input file)

fstream    : Stream class to both read and write from/to files (file)

These classes are derived directly or indirectly from the classes istream, and ostream. We have already used objects whose types were these classes: cin is an object of class istream and cout is an object of class ostream. Therefore, we have already been using classes that are related to file streams. And in fact, we can use our file streams the same way we are already used to use cin and cout, with the only difference that we have to associate these streams with physical files. Let’s start with an example.

PROGRAM 76

Q. Write a program to write a line of text content into a file named “example.txt” using output-file stream Class with an object named myfile. (You can check the file example.txt after program execution to see if the content is written)

#include <iostream>

#include <fstream>

using namespace std;

main ()

{

   ofstream myfile;

   myfile.open("example.txt");

   myfile << "I am studying Files in C++ and writing this to a text file.\n";

   myfile.close();

}

 

This code creates a file called example.txt in the directory in which your CPP program is running (in this example its F:\Dev-Cpp\ProgramFiles), and inserts the line of text within quotes, into the file named example.txt. It is similar to cout, but here, the content is written into a text file and not onto the monitor.




 





















Let’s look further into the details of using files in C++.


OPENING A FILE

We can open a file with a stream object using open() and its syntax is:

  open (filename, mode);

Where filename is a null-terminated character sequence of type const char * (the same type that string literals have) representing the name of the file to be opened, and mode is an optional parameter with a combination of File Mode flags as shown in the chart below.

Eg: myfile.open("example.txt");

File Open Modes in C++ _ ajit saigal


Two or more these flags can be combined using the bitwise operator OR (|). For example, if we want to open the file example.bin in binary mode to add data we could do it by the following call to member function open():


ofstream myfile;

  myfile.open ("example.bin", ios : out | ios : app | ios : binary);

 

If the file mode is not specified along with an open(), the corresponding default mode is set automatically for the classes ofstream, ifstream, and fstream.

 

Class

Default Mode Parameter

ofstream

ios :: out

ifstream

ios :: in

fstream

ios :: in | ios :: out



When no file open mode is specified for the ifstream classes, ios::in is assumed by default, and for ofstream classes, ios::out is assumed. If the function is called with any file mode parameter, the default mode is overridden (not considered).

File streams that are opened in the binary mode, perform input and output operations independent of any format considerations. Example to open a file in binary mode is: 

ofstream myfile (“example.bin”, ios::out | ios::app | ios::binary);

To check if a file stream has successfully opened a file, you can call the fail() with no arguments. This member function returns boolean value TRUE if the file did not open “because the file doesn’t exist”. It returns false if the file exists. Most importantly, if the file did not exist, come out of the program immediately using the exit(0) command as there is no point proceeding with execution of the remaining program lines. Declare the header file stdlib when using exit(). The general format for fail() is:

if ( myfile.fail() )

   {

     /*  do not proceed as File is non-existent and so did not open  */

     exit(0);

     }

else

{

  /*  proceed with the program to read/write into a file  */

 }


NOTE: exit(0) indicates successful program termination and exit(1) indicates unsuccessful program termination.




CLOSING A FILE

When we have finished with input / output operations on a file, we will close it so that its resources become available again for other operations. The close() is used to close an opened file. This member function takes no parameters, and flushes the associated buffers to close the file.

Eg:  myfile.close();

Once this member function is called, the stream object can be used to open another file, and the file is available again to be opened by other processes. In case that an object is destructed (remember constructor/destructor) while still associated with an open file, the destructor() automatically calls the close().

Text Files

Text file streams are those where we do not include the ios::binary flag in their opening mode. These files are designed to store text and thus all values that we input or output from/to them can suffer some formatting transformations, which do not necessarily correspond to their literal binary value. Data output operations on text files are performed in the same way we operated with cout.


PROGRAM 77

Q. Write a program to write 2 lines of text matter into a file named “example2.txt” using the output-file stream class with myfile as the object. Use fail() to check if file stream successfully opened the file.

#include <iostream>

#include <fstream>

/* if you are using Turbo C++ add header file <stdlib.h> */

using namespace std;

main ()

{

    ofstream myfile ("example2.txt");

         if (myfile.fail())

             {

                  cout<<"Unable to Open File ... No such file";

                  exit(0);

               }

    myfile << "This is first line.\n";

    myfile << "This is second line.\n";

    myfile.close();

    cout << "File Open is Successful ...";

}

OUTPUT


Question: Test Your Understanding

 

In the main() of above program, if you


replace this line:

ofstream myfile ("example2.txt");


with this line:

ofstream myfile ("");


Can you guess what would happen?

 

Answer: The fail() and exit() would work and nothing will be written into the file example2.txt !!!  The C++ compiler will display message like this:





FILE INPUT FUNCTIONS


File input functions are used to fetch data from a file. Common input functions include:

 

(i) Reading of Character Data


get() is used to read a character from the file. Data input can be from a file into a variable or from one file to another file. Syntax of get() is:

file_object_name.get(variable);

 

(ii) End Of File


eof() checks if End-Of-File has reached. This function returns a boolean value TRUE when program control reaches the end of a file.

 

(iii) Reading of Numeric Data


>> operator is used to read numeric data from the file. Syntax is:


file_object_name >> variable; 


PROGRAM 78

Q. Write a program to read text matter from the file named “example2.txt” using the input-file stream class with an object named myfile. If the file exists, write file contents onto the screen until end of file contents.

Note: The file example2.txt was created in the previous program.

 

#include <iostream>

#include <fstream>

using namespace std;

/* if using turbo C++ include the header file <stdlib.h> */

main ()

{

  char ch;

  ifstream myfile ("example2.txt");

  if (myfile.fail())

  {

     cout<<"\nUnable to Open File ...\n";

     exit(0);   // goes out of the program if the File doesn't exist

  }

   cout<<"\nFile Open Successful. Contents are: \n";

   while (!myfile.eof() )    //  if eof is not reached then proceed…

    {

      myfile.get(ch);

      cout << ch;

    }

    myfile.close();

}

 

OUTPUT








Above program reads the text file and prints out its content onto the screen. Notice how we have used eof() that returns true in the case that the end of the file has been reached. We have created a while loop that finishes when myfile.eof() becomes true (when end-of-file has reached) and we have used the get() for reading character by character from the file.

FILE OUTPUT FUNCTIONS

File output functions are used to write data into a file. Common output functions include:

 

(i) Writing of Character Data

 

put() is used to write a character into the file. Syntax is:

file_object_name.put(variable);

 

(ii) Writing of Numeric Data


<< operator is used to write numeric data into the file. Syntax is:

file_object_name << variable;


PROGRAM 79


Q. Write a program to create a file (MarkList). Accept the name and 2 marks of a student. Write them into the file. Then read from the file and print the details with total marks.



#include <iostream>

#include <fstream>

using namespace std;

main()

{

          /* open file for output or writing into file */

         ofstream OutFile("MarkList");

          char name_out[20], name_in[20];

          int i, tot, m_out[2], m_in[2];

          cout<< "Enter Name: ";

          cin>>name_out;

          OutFile<<name_out;

          for(i=0;i<2;++i)

          {

                cout<< "Enter Mark: ";

                cin>> m_out[i];

               /* "\t" is used to separate fields in the file */

                OutFile<<"\t"<<m_out[i];

            }

          OutFile.close();

          /* open file for input or reading from file */

          ifstream InFile("MarkList");

          cout<< "\n\nM=A=R=K L=I=S=T\n\n";

          while(! InFile.eof())

          {

                      InFile>>name_in>>m_in[0]>>m_in[1];

                      cout<<name_in<<"\t";

                      cout<<m_in[0]<<"\t";

                      cout<<m_in[1]<<"\t";

          }

          tot=m_in[0] + m_in[1];

          cout<<"\n\nTotal Marks = "<<tot;

          InFile.close();

}


OUTPUT












READING & WRITING A SET OF CHARACTERS 

(i) read()

The read function is used to read a set of characters from the file. Syntax is:

file_object_name.read((char*) &variable_name, sizeof(variable_name));

(ii) write()

The write function is used to write a set of characters into the file. Syntax is:

file_object_name.write((char*) &variable_name, sizeof(variable_name));

Checking STREAM-STATE Flags

In C++, the state of a stream can be checked by built-in member functions that return a boolean value (flag). Most common functions that help check the state of C++ stream includes:

 

bad() : Returns TRUE if a reading or writing operation fails. For example, in the case that we try to write to a file that is not open for writing, or if the device where we try to write has no space left.

fail()   : Returns TRUE as in the same cases of bad(), but also in the case that a format error happens, like when an alphabetical character is extracted when we are trying to read an integer number.

eof()    : Returns TRUE when reading a file has reached the end of file.

good() : It is the most generic state flag. It returns FALSE in the same cases in which calling any of the previous functions would return TRUE.

We can use clear() to reset the stream-state flags checked by any of these member functions. 

INTERNAL STREAM POINTERS : get, put

All i/o stream objects have at least, one internal stream pointer.

(i) get Pointer: The get pointer belongs to ifstream and istream objects. It points to the location from where next element for input operation will be read.

(ii) put Pointer: The put pointer belongs to ofstream and ostream objects. It points to the location to which next element for output operation will be written.

The fstream object inherits ‘get’ and ‘put’ pointers from iostream (iostream is derived from both istream and ostream).

MANIPULATION OF INTERNAL STREAM POINTERS

The internal stream pointers that point to the reading or writing locations within a stream can be manipulated using the following member functions:

1.     tellg(), tellp()

 

The tellg() gives us current position of the get pointer (input file pointer).

The tellp() gives us current position of the put pointer (output file pointer).

The tellg and tellp member functions have no parameters and return a value of the DATA TYPE pos_type. (pos_type is an “integer data type” representing the “current position” of the get stream pointer for tellg or the put stream pointer for tellp).

2.     seekg(),  seekp()

The seekg() helps to reposition the get pointer (input file pointer) to any required position.

The seekp() helps to reposition the put pointer (output file pointer) to any required position.

Both these functions are overloaded with "2 different prototypes":

(1) First Prototype for seekg(), seekp()

seekg ( position );

seekp ( position ); 

Using this prototype, the stream pointer is changed to the absolute position (counting from the beginning of the file). The “data type” for this parameter is same as the one returned by functions tellg and tellp (pos_type, which is an integer value).

(2) Second Prototype for seekg(), seekp()

seekg ( offset, direction );

seekp ( offset, direction );

Using this prototype, the position of ‘get’ or ‘put’ pointer is set to an offset value relative to some specific point determined by the direction. ‘offset’ is of the data-type off_type, which is an integer data type. ‘direction’ is of data-type seekdir, which is an enumerated type (enum) that determines the point from where offset is counted. We can use three directions for the offset values:

DIRECTION / SEEKDIR

MEANING

ios :: beg

beginning of a file

ios :: end

end of a file

Ios :: cur

current position of a file


For Example: 
seekg (14, ios :: beg) means go to 14th position from Beginning of File.

PROGRAM 80

Q. Write a program to find out the size of a file.

Note: I have used the file example2.txt from our previous programs.

#include <iostream>

#include <fstream>

using namespace std;

main ()

 {

   long begin, end;

   ifstream myfile ("example2.txt");

   begin = myfile.tellg();

   myfile.seekg (0, ios::end);

   end = myfile.tellg();

   myfile.close();

   cout << "SIZE of the File is: " << (end - begin) << " bytes.\n";

}

 

OUTPUT
















READING & WRITING A CLASS OBJECT

read()

The read function is used to read a class object from the file. Syntax is:

file-object-name. read ((char *) &object-name, sizeof (object-name));

Eg: PhoneDiary.read((char*) &BookEntry, sizeof(BookEntry));

 

write()


The write function is used to write a class object into the file. Syntax is:

file-object-name. write ((char *) &object-name, sizeof (object-name));

Eg: PhoneDiary.write((char *) &BookEntry, sizeof(BookEntry));


PROGRAM 81

 

Q. Write a program using read() and write() to create Phone Book of customers for a shop. It must store, retrieve and print name, phone no, and age of one or more people.


#include <iostream>

#include <fstream>

using namespace std;


class TelephoneBook

{

         private:

                     char name [30];

                     char phone[20];

                     int age;

         public:

                     void ReadData();

                     void PrintData();

 };

 void TelephoneBook :: ReadData()

         {

                     cout<<"Customer Name  : ";

                     cin.getline(name, 30);  // accept name with space

                     cout<<"Customer Ph.No : ";

                     cin.getline(phone, 20);

                     cout<<"Customer Age   : ";

                     cin>>age;

         }

 void TelephoneBook :: PrintData()

         {

                     cout<<"\nName: "<<name;

                     cout<<"\nPh. : "<<phone;

                     cout<<"\nAge : "<<age;

         }


main ( )

{

  fstream            PhoneDiary;  

  TelephoneBook  BookEntry;         

  char                 UserChoice;   

 

  UserChoice = 'y';

  PhoneDiary.open("PhoneBook",ios::out); /* open file for read, write */

  while (UserChoice == 'y' || UserChoice == 'Y') /* accept, write data to file */

  {

     BookEntry.ReadData();

     PhoneDiary.write((char *) &BookEntry, sizeof(BookEntry));

     cout << "Do you want to enter more records? [Y/N] : ";

     cin >> UserChoice;

     cin.ignore(); /* removes unwanted space which auto skips next entry */

   }

  PhoneDiary.close();

  PhoneDiary.open("PhoneBook",ios::in); /* move get pointer to the start */

  PhoneDiary.seekg(0,ios::beg);

  cout<<"\nP=H=O=N=E B=O=O=K\n";

  while (PhoneDiary.read((char*) &BookEntry, sizeof(BookEntry))) /* EOF */

  {

     BookEntry.PrintData();

     cout<<"\n-----------------\n";

   }

   PhoneDiary.close();

 }


OUTPUT
















 
C++ TEMPLATES

In C++ the template defines a family of “functions” or "classes” that can operate on different types of information. This allows a function or class to work on many different data types without being rewritten for each one.


FUNCTION TEMPLATES

Function templates are special functions that can operate with generic types. This allows us to create functionality that can be adapted to more than one type or class without repeating the entire code for each type. In C++ this can be achieved using template parameters.

A template parameter is a special kind of parameter that can be used to pass a type as argument. Just like how regular function parameters can be used to pass values to a function, template parameters allow to also pass types to a function. The function templates can use these parameters as if they were any other regular type. The format for declaring function templates with type parameters is:

template <class typename> return-type  func-name (parameter list)

{

   // body of function

}

 

Refer to following program on how to use C++ Templates.

 

PROGRAM 82

 

Q. Create a template function that returns the greater of two objects.

 


#include <iostream>

using namespace std;

template <class myType>

myType GetMax(myType a, myType b) {return (a>b?a:b);}

main()

{

 cout<<"Greater value is "<<GetMax(21,22);

}


OUTPUT


  Greater value is 22  .

 

Here we have created a template function with myType as its template parameter. This template parameter represents a type that has not yet been specified, but that can be used in the template function as if it were a regular type. The function template GetMax receives 2 parameters a, b of type myType. After processing the 2 values, GetMax function returns the bigger of two parameters.

 

When C++ compiler encounters the functional call to template function GetMax, it uses the template to automatically generate a function replacing each appearance of myType by the type passed (for a, b) as the actual template parameter (integer, in this case) and then calls it. This process is automatically performed by the compiler and is invisible to the programmer. Here is another example.


Applying Function Template



PROGRAM 83

Q. Use a Function Template to accept two numbers from keyboard and find biggest among them. Then accept two characters from keyboard and find biggest character using the same Function template.


#include <iostream>

using namespace std;

template <class T>

T GetMax(T a, T b)

{T result;

   result = (a>b) ? a : b;

   return (result);

}

main ()

{

   int i, j; char ch1, ch2;

   cout << "Enter 1st number : "; cin>>i;

   cout << "Enter 2nd number : "; cin>>j;

   cout << "Bigger number is   : "<<GetMax(i, j)<<"\n\n";

   cout << "Enter 1st  character: "; cin>>ch1;

   cout << "Enter 2nd character: "; cin>>ch2;

   cout << "Bigger  character is: "<<GetMax(ch1, ch2);

}


OUTPUT












As you can see, the template “type T” is used in GetMax() as parameter declarations (a, b) and then within it to declare new object (result).

Therefore, result will be an object of same type as the parameters a and b when the function template is instantiated with a specific type. In this specific case where the generic type T is used as a parameter for GetMax() the compiler can find out automatically which data type has to instantiate without having to explicitly specify it. So we have used:

int i, j;

GetMax (i, j);

 

and then we used,


char ch1, ch2;

GetMax (ch1, ch2);




No comments:

Post a Comment