At the end of the chapter, you will be able to understand and program
Unformatted and formatted stream operators.
Use IO manipulator to format output.
Sequential and random/direct access file handling.
Read objects from and write objects onto a file
What crosses your mind when you think of streams? Probably streams of water, we call them springs, flowing from the top of a hill to plains. In C++, we call streams or IO streams.
This chapter will introduce to you unformatted and formatted input and output streams. It deals extensively with stream manipulators that are used to format and control stream data. The chapter also concentrates on file handling in C++ through <fstream> header file. The concepts covered are sequential file handling and random/direct access techniques. The techniques to handle formatted data and raw data are discussed. We will wrap up the chapter with object read and write operations onto a file.
In C++, IO streams are flow of bytes from one input device to memory and vice versa. A stream is like a pipe. It can carry anything in the pipe, be it kerosene, milk, water, etc. – refer to Figure 13.1 shown below.
Figure 13.2 IO Streaming – A close look
Streams output whatever is inputted.
The library functions are classified as Console IO, Disk IO and Port IO. Port IO are used for input and output programming, when we want to use ports for data input and output.
Disk IO: This mode of operation is performed on entities called files. Usually, writing onto files and reading from the files are never done directly onto disk. Instead, a buffer (a memory) is used to store prior to writing onto file and after reading from the file. Buffering in case of Disk IO is essential for saving access time required to access memory. DiskIO is of two types:
Console IO: All the input and output functions control the way input has to be fed and the way output looks on standard output devices, i.e. screen. These IO statements are further classified as formatted and unformatted.
In order to perform I/O operations, a stream is attached to an I/O device. Typical I/O devices include consoles, keyboards, files and electronic devices like sensors. The inserters represented by the “<<” symbol work as translators which translate in memory representation of data types such as integers, floats and user-defined data types into data types which can be understood by the I/O devices. The extractor represented by the “>>” symbol translates data sent by I/O devices to in memory representation formats such as integers and floats. Typical I/O devices like consoles and keyboards send and receive data in ASCI format.
Let us see with an example how extractors and inserters work. Consider the following piece of code int n; cin >> n; Now using the keyboard, assume the user has entered numbers 6, 7 and 8 followed by the enter key. Following this operation, the buffer associated with the input stream would look like Figure 13.3.
Figure 13.3 Representations of input stream
ASCII representation of individual numbers is as follows:
6 = 0 × 36 = 0011 0110 7 = 0 × 37 = 0011 0111 8 = 0 × 38 = 0011 1000
Through the statement cin >> n extractor knows that the input stream should be formatted into an integer as n is of the type integer. The extractor then proceeds to extract each character from the stream and converts it into decimal value. To get equivalent decimal values from ASCII format, the extractor subtracts ASCII value of 0(0 × 30) from each character in the stream.
‘6’ – ‘0’ = 0 × 36 – 0 × 30 = 6 : ‘7’ – ‘0’ = 0 × 37 – 0 × 30 = 7 : ‘8’ – ‘0’ = 0 × 38 – 0 × 30 = 8
The extractor continues to do the above operation till it encounters ‘ ’, carriage return (CR) in the input stream. It also stops extracting if it encounters Tab, Space and EOF markers. During extraction, the extraction operator also keeps a count of numbers or characters it has extracted and accordingly sets the place value of each digit. In our case, 6 is assigned a place value of 100, 7 a place value of 10, and 8 a place value of 1. The last step involves multiplying the extracted decimal values with their corresponding place values and adding them up to get integer representation: n = 6*100 + 7*10 + 8*1 = 678. But in memory, representation is in the form of integer, so 678 will be represented as:
678 = 0 × 2A6 = 0000 0010 1010 0110.
The inserter works in exactly the opposite way. As seen from the above example, iostream library object cin coupled with the extractor operator >> provides the user translation services and also the processing of special characters such as Carriage Return(CR), Space, Tabs and End of File(EOF). This kind of I/O is called formatted or high-level I/O. Formatted I/O abstracts the user from inner workings of streams and is easier to use. The disadvantage of formatted I/O is that it is slow and not suitable for large data sizes.
Unformatted I/O is also called low-level I/O. It offers the highest efficiency and throughput amongst all the other I/O mechanisms. Unlike formatted I/O, here input has no automatic whitespace, Tab, carriage return detection and processing, and also data is not formatted – the programmer has to interpret the data.
Input:
get():
get(char& ch):
get(char* str, int count, char delim=’ ’):
getline(char* str, int count, char delim=’ ’):
read(char* str, int count) :
Output:
put(char ch):
write(const char* str, int count):
Miscellaneous:
putback(char c)
peek()
ignore( streamsize num=1, int delim=EOF ):
Consider the following piece of code:
cout <<”
Enter source file name..: “;
cin>>filename;
cout<<”
Enter text for inputting to file …”<<endl;
cin.ignore(1,’
’);
cin.getline(text,80);
Now suppose you have entered thunder.txt and pressed enter at the first prompt the operation cin>>filename reads the input stream stores filename with the value thunder.txt but the cin operator does not extract the extra enter (‘ ’) key that you have inputted. Now suppose that we do not include cin.ignore(1,’ ’) and directly call cin.getline(text,80), it will return NULL as first character in the stream is ‘ ’ the default delimiter for getline(). To avert this situation, we ignore the operation to discard the ‘ ’ character present in the input stream.
Example 13.1: unformatedio1.cpp Program to Show cin.get()) to Read a Character
1. #include<iostream>
2. #include<cstring>
3. using namespace std;
4. void main()
5. {char ch, str[10];
6. cout<<”
Enter any string : Showing character input thru cin.get() :”;
7. while((ch = cin.get()) != ‘
’) // using get() function
8. cout << ch;
9. cout<<”
Enter a string<Less Than 9 or less characters : cin.read>: “; //using read fn
10. cin.read(str, sizeof(str));
11. str[9] = ‘ ’;
12. cout << endl << str;
13. }
/*Output: Enter any string: Showing character input through cin.get() :Hello World
Hello World
Enter a string<Less Than 9 or less characters : cin.read>: hello USA*
Line No 7 Shown cin.get() . Line No 10 shows cin.read() . Note that read() also works with cin object.
Example 13.2: unformatio2.cpp Program to Show Unformatted Output Functions
1. hello USA*/
2. #include<iostream>
3. #include<conio.h>
4. #include<string.h>
5. using namespace std;
6. void main()
7. { int i;
8. char str[] = “I enjoy programming in C++” ;
9. for(i = 0 ; str[i] != ‘ ’; i++) cout.put(str[i]); //using write function
10. cout<<endl; cout.write(str, strlen(str)); getch();
11. }
/*Output I enjoy programming in C++ I enjoy programming in C++*/
Line No 9 shows usage of cout.write(). Note that write works with cout also.
I/O library in C++ provides a mechanism to test whether a particular I/O operation has succeeded or failed. Each stream object maintains a set of flags which indicate the state of the stream after an I/O operation. Library also provides set of member functions which can be used to test the flags. The flags and the corresponding member functions are shown in the Table 13.1.
Table 13.1 Flags and member fuctions
Flag Name | Description | Testing Function |
---|---|---|
goodbit | Set to 1 when stream encounters no errors | good() Ex: cin.good() |
eofbit | Set to 1 when stream encounters end of file | eof() Ex: cin.eof() |
failbit | Set to 1 when stream encounters an error but is recoverable | fail() Ex: cin.fail() |
badbit | Set to 1 when stream is corrupted and is unrecoverable | bad() Ex:cin.bad() |
#include<iostream>
#include<conio.h>
using namespace std;
void main()
{int value;
cout << “Enter Value: “;cin >> value;
cout <<endl <<”goodbit: “<< cin.good();cout <<endl <<”eofbit : “<< cin.eof();
cout <<endl <<”failbit: “<< cin.fail();cout <<endl <<”badbit : “<< cin.bad();
cout <<endl <<"Enter Value(enter characters to see effect on flags): ";cin >> value;
cout <<endl <<"goodbit: "<< cin.good();cout <<endl <<"eofbit : "<< cin.eof();
cout <<endl <<”failbit: “<< cin.fail();cout <<endl <<”badbit : “<< cin.bad();
getch();
}
/* Output : Enter Value: 47 goodbit: 1eofbit : 0failbit: 0badbit : 0
Enter Value(enter characters to see effect on flags): ghj :
goodbit: 0eofbit : 0failbit: 1badbit : 0*/
The <iostream> header file allows byte of data to flow from source to destination. Stream is independent of what data type is getting streamed or the source of destination.
C++ supports istream for input and ostream for output. IO stream library includes four types of predefined streams:
cin : for standard buffered input
cout : for standard buffered output
cerr : for unbuffered error output. Works just like cout
clog : for buffered log
<iomanip> header file consists of several functionalities to handle formatted output such as setw () setprecision(), etc.
<fstream> contains all the programs needed for file handling. The hierarchy of IO stream is shown in Figure 13.4.
Example 13.4: io1.cpp Program to Show Cin and Cout at Work
#include<iostream>
using namespace std;
void main()
{double price; char title[30]; char author[30];
char * tell = “ Enter the title of the Book, Author and price :”; cout<<tell;
cin>>title>>author>>price; cout<<”
Tile of the book :”<<title<<endl;
cout<<”
Author of the book :”<<author<<endl;
cout<<”
Price of the book :”<<price<<endl;
}
/*Output :Enter the title of the Book, Author and price :C++ ramesh 250.00
Tile of the book :C++ : Author of the book :ramesh : Price of the book :250*/
Manipulators alter the status of streams. For using this feature we need to include the statement: #include<iomanip> in global section. For example, if we use a manipulator setprecision(2), all the floating point variable output will be two digits after decimal point. A few of the important IO manipulator are:
cout<<dec<<intvar;decimal / hexa / octal representation from integers
cout<<hex; cout <<oct;
cout<<setiosflags(ios::dec) Sets the formatting bits as decimal
cout<<resetiosflags(ios::hex) Resets already set flags as per format specified
cout<<setbase(int n) :Sets bas to n
cout<<setw(int n) :specifies width for output formatting
cout<<setfill(“*”); :fills the unfilled space set with setw() with fill character
Character manipulators are shown in Table 13.2. Numberic and Data stream manipulators are shown in Tables 13.3 and 13.4, respectively.
Table 13.2 Character manipulators
Manipulator | Affected Flag | Description |
---|---|---|
setw(val) | None | Sets the width of output filed to the specified value |
setfil(char) | None | Pads the unfilled width of the output with the specified character |
right | ios::right | Right justifies the output |
left | ios::left | Left justifies the output |
internal | ios::internal | Left adjusts the sign and right adjusts the value |
Table 13.3 Numeric manipulators
Manipulator | Affected Flag | Description |
---|---|---|
dec | ios::dec | I/O uses decimal notation for input and output |
hex | ios::hex | I/O uses hexadecimal notation for input and output |
oct | ios::oct | I/O uses octal notation for input and output |
scientific | ios::scientific | Display floating point number in scientific notation |
fixed | ios::fixed | Display floating point number in fixed notation |
setprecision(n) | None | Sets precision of floating point variables to n |
Table 13.4 Data stream manipulators
Manipulator | Affected Flag | Description |
---|---|---|
endl | None | Inserts newline character in the stream and flushes (sends) the buffer to output |
flush | None | Flush the output buffer to the console |
ws | None | Ignore white spaces in the input |
cout<<endl; :new line to iostream and flushes the buffer.
cout<<flush; :flushes ostream buffer
cout<<ends; :inserts null character at the end
Method 1: Using setiosflags to manipulate flags
cout<< setiosflags(ios::left);
cout << setw(10) << setfill(‘.’) << “Hello” ;
Method 2: Using Manipulators
cout << left <<setw(10)<<setfill(‘.’)<<”Hello” ;
Example 13.5: io2.cpp Program to Show Cin and Cout at Work
1. #include<iostream>
2. #include<iomanip>
3. using namespace std;
4. void main()
5. {double price; char title[30]; char author[30]; int copies;
6. char * tell1 = “ Enter the title of the Book :”;
7. char *tell2 = “ Enter the Author of the Book :”;
8. char *tell3 = “ Enter the price of the Book :”;
9. char *tell4 = “ Enter No of copies of the Book :”;
10. cout<<tell1<<flush;
11. cin>>ws>>title; cout<<tell2<<flush; cin>>author; cout<<tell3 <<flush;
12. cin>>price; cout<<tell4<<flush; cin>>dec>>copies;
13. cout<<setiosflags(ios::left)<<”
Title of the book :”<<title <<endl;
14. cout<<”
Author of the book :”<<author<<endl;
15. cout<<resetiosflags(ios::right)<<”
Price of the book :”<<setw(10) <<price<<endl;
16. cout<<”
Number of copies :”<<setw(10)<<copies<<endl;
17. }
/*Output: Enter the title of the Book :C++ : Enter the Author of the Book :Ramesh
Enter the price of the Book :250 :Enter No of copies of the Book : 10000
Title of the book :C++ :Author of the book :Ramesh : Price of the book :250
Number of copies :10000 */
Line No. 10: | shows that we need to use flush() to flush the buffer on to IO device. |
Line No. 11: | instructs ws meaning accept white spaces while taking in title. Of course, once set, the flags continue to be set unless cancelled by altering the flag. |
Line No. 12: | shows flush() and decimal setting. Line No 13 shows left justification. |
Line No. 15: | shows setw(10) meaning width of 10. It also restsiosflag to right. |
The arguments that can be passed to setiosflag and resetiosflags manipulators are shown below:
ios::skipws | skip white spaces in input stream |
ios::left or ios::right | left or right justification |
ios::scientific | |
ios::fixed | follows decimal notation for floating point numbers |
ios::hex,ios::oct | |
ios::showbase | outputs the base number system |
ios::showpoint | shows decimal point compulsorily. |
Ios::showposs | shows + sign while displaying positive numbers |
We would come across files everywhere we go. For example, college holds a file for each of their students. Similarly municipality holds files containing details of taxes to be paid by citizens. Indeed files are so common in our lives, C++ language and other languages support files. What is a file? A file is a collection of records. Figure 13.2 shows a file named student.dat with n records belonging to n number of students.
A record in a physical file is a data sheet wherein details of a student are recorded. There will be as many records as there are students. In a C++ file too, there will be records, again one for each student. Figure 13.5 shows a record.
Figure 13.5 File and records
A record in turn contains fields. Figure 13.6 shows a record and fields contained therein.
Figure 13.6 Record and fields
Files can be classified based on the way they are accessed from the memory as
Sequential File: All records are stored sequentially as they are entered. This type of file is best suited when we have to access all the records in sequence one after the other. Marks processing of a class is an example.
Random Access File: In this mode of access, a record is accessed using an index maintained for this purpose. It is like browsing through a chapter and within the chapter a page of interest using the index provided at the beginning of the book.
Direct Access File: In this mode, the records are stored based on their relative position with respect to the first record. For example, record 50 will be 50 lengths away from the address of record 1. The main advantage of this mode of access is that there is no need to maintain indexes that would result in memory overhead. The disadvantage is that memory locations get blocked.
C++ language supports both sequential and direct access mode.
Files can be further classified as text files or binary files. Normally, in a text file, data is stored using ASCII character code. Thus, to store 1234.5 in text mode, we would need 6 character spaces, i.e. 48 bits, whereas if you store it in binary mode, one would save a lot of memory as we will convert 1234.5 into binary and then store. Hence, for storing intrinsic data of large numbers and sizes, binary mode is always preferred.
The classes required in connection with file handling in C++ are all kept in fstream header. Therefore, insert a statement : #include<fstream>
To open a file for writing data on to it, we would create an object of ofstream like this:
ofstream outfile(“Student.dat”);
To open a file for reading data from it, we would create an object of ifstream like this:
ifstream infile(“Student.dat”);
We need to check if infile stream has been successfully allocated. In C++, logical NOT has been overloaded to check the stream file creation
if(!infile) {cerr<<”
Sorry cannot open the file infile..”<<endl; exit(1);}
After use, every file that is opened needs to be closed like this outfile.close(); infile.close();
It is possible to control the stream files opening modes. We need to include these mode switches while creating the object through constructors.
We will write a program to copy a file's contents onto another file . In Example 13.6, we would use command line arguments feature. With commandline argument, you can execute the program from command line prompt C:> iop io2.cpp io2copy.cpp There are three arguments, namely, argv[0] = io2.cpp argv[1] = io2.cpp is the source. argv[2] = io2copy.cpp is the destination file. This feature allows us to execute the program without invoking IDE of Turbo C++ or VC++ directly from the command line prompt.
Example 13.6: io3.cpp Program to Copy a File Through Command Line Arguments
#include<fstream>
#include<iostream>
using namespace std;
void main(int argc , char **argv)
{if ( argc<3)
{cout<<”
correct usage of command line argument is : copyfile inputfile
outputfile..”<<endl; exit(0); }
// open inputfile and connect it to input stream inputstream
ifstream inputstream(argv[1]);
if(!inputstream)
{ cout<<”
cannot open the input file ..”<<argv[1]<<endl; exit(1); }
//open the output file and connect it to outputstream
of stream outputstream(argv[2]);
if(!outputstream)
{ cout<<”
cannot open the output file ..”<<argv[2]<<endl; exit(1); }
// now read from input file and copy to output file
char ch;
while ( (inputstream.get(ch)) && outputstream ) outputstream.put(ch);
}
We have shown another version in which we obtain the file names from the user and execute copy source file onto the destination file in the solved example section, Ex 2 at the end of the chapter.
Example 13.7: io5.cpp Open a File in Append Mode, Append a Line
#include<fstream>
#include<iostream>
using namespace std;
void main()
{ char filename[30];
char text[80]; // for user input
cout <<”
Enter source file name..: “;
cin>>filename;
//Now lets open the file once again for append mode
ofstream outfile(filename,ios::app);
if(!outfile)
{ cout<<”
cannot open the input file for appending..”<<filename <<endl;
exit(1); }
cout<<”
Enter text for inputting to file …”<<endl; cin.ignore(1,’
’);
cin.getline(text,80); outfile<<text<<”
”;outfile.close();
cout<<”
completed writing to output file”<<endl;
// now lets read the file, we have just outputted our text for confirmation
cout<<filename<<endl;
ifstream infile(filename);
if(!infile)
{cout<<”
cannot open the input file ..”<<filename<<endl; exit(1);}
char ch;
while ( infile.get(ch)) // now read from input file and copy to output file
cout<<ch;
cout<<”
display process completed..”<<endl;
infile.close();
}
/*Output:
Enter source file name..: io4.cpp : Enter text for inputting to file …
Hi we are trying out appending through io5.cpp : completed writing to output file
Hi we are trying out appending through io5.cpp : display process completed..*/
Note that C++ supports all form of input and output statements of C language. You can freely use them in C++. We have used the following statements in the program
char text[30]; // buffer for user input
cin.getline(text,30); // getline takes in to buffer text maximum of 30 characters
// But new line character
is ignored and not taken in
cin.ignor(1,’
’); // ignores 1 character shown as second argument
Normally, to facilitate direct reading on the console, the files are stored in text format. But for efficiency and saving the memory space, it would be far more efficient to store the data in binary form, i.e. in 0 s and 1 s. For example, a number 50595 is stored by text file as ‘5’, ‘0’, ‘5’, ‘9’, ‘5’, whereas the binary form will allocate 2 or 4 bytes depending on the hardware used and stores the number as binary equivalent >. In C++ a flag called ios::binary will specify the mode.
A binary file can be used to store all the intrinsic data types as well as user-defined data types like objects. We will use write() to write data on to binary files and read() to get the data from binary files.
Student std ( 20 , 70) ; // student object with roll number and average marks
fileobject.write( ( char*) & std , sizeof (std) );
fileobject.read( ( char*) & std , sizeof (std) );
Example 13.8: io6.cpp Program to Write a Class Called Student on to a File and Read Back the Contents of the File
#include<iostream>
#include<fstream>
using namespace std;
//declare a class called Student
class Student
{ public: Student(int n, char *p, double d) {rollNo=n,name=p, total =d;}
~Student(){}; // Default destructor
// public access functions
int GetRollNo() const { return rollNo;}
void SetRollNo ( int n) { rollNo=n;}
char * GetName() const { return name;}
void SetName( char *p) { name=p;}
double GetTotal() const { return total;}
void SetTotal ( double d) { total=d;}
private: int rollNo; char *name;double total; // name is a pointer to name
};
void main()
{ char filename[80];
cout<<”
Enter file name…:”;
cin >>filename;
ofstream outfile(filename,ios::binary); // open in bibnary mode
if(!outfile) cout<<”
Cannot open iffile in binary mode..”<<filename<<endl;
exit(1); }
Student std(5095,”Thunder”,70.0); // create a student object and write on to file
cout<<”
Data of Student we have created..”<<endl;
cout<<”
Student roll number : “<<std.GetRollNo()<<endl;
cout<<”
Student name : “<<std.GetName()<<endl;
cout<<”
Student total : “<<std.GetTotal()<<endl;
outfile.write( (char*) & std , sizeof std ); outfile.close();
// now lets open the file and read the content
ifstream infile(filename,ios::binary);
if(!infile)
{ cout<<”
Cannot open infile in binary mode..”<<filename <<endl;
exit(1); }
// we will create a dummy std2 and read the data from file on to std2
Student std2(1,”No Name”,0.0);
infile.read( (char*) &std2 , sizeof(std2) );
cout<<”
Data of Student read from file..”<<endl;
cout<<”
Student roll number : “<<std2.GetRollNo()<<endl;
cout<<”
Student name : “<<std2.GetName()<<endl;
cout<<”
Student total : “<<std2.GetTotal()<<endl;
}
/*Output: Enter file name…:stdbinary: Data of Student we have created..
Student roll number: 5095: Student name: Thunder: Student total: 70
Data of Student read from file..
Student roll number: 5095: Student name: Thunder: Student total: 70*/
In C language, you have used, fseek() and ftell() to position the read & write cursor on the file. In C++, we will use seekg() and seekp() for get position and seek position. This is because in C++ the same stream is used for both input and output.
Seekg() alters the get position, i.e. the position from where we can read from a file.
Seekp() alters the position from where we can write.
infile.seekg(256); // skip 256 bytes and position get cursor at position 217
outfile.seekp(1024); // position the cursor for writing at byte position 1025
tellg() and tellp() functions on the other hand tell us about the position of read and write during our next read and write operation.
int pos = infile.tellg() ; // indicates the position of next read operation.
int pos = infile.tellp() ; // indicates the position of next write operation.
#include<iostream>
#include<fstream>
#include<iomanip>
using namespace std;
const int max =3;
//declare a class called Student
class Student
{ public:
Student(){}
~Student(){}; // Default destructor
// public access functions
void GetData(void);
void DisplayData(void);
private: int rollNo; char name[20]; float mat,sci,eng,total,avg;};
void Student::GetData(void)
{ cout<<”
Enter name : “;cin>>name; cout<<”
Enter id No : “;
cin>>rollNo;
cout<<”
Enter <Maths , Science and English> Marks :”; cin>>mat>> sci>>eng;
total = mat+sci+eng; avg=total/3.0; }
void Student::DisplayData(void)
{ cout<<"
Name :"<<setiosflags(ios::left)<<setw(20)<<name;
cout<<"
Total :"<<setprecision(2)<<setw(20)<<setiosflags(ios::fixed)<<total<<endl;
cout<<"
Average :"<<setprecision(2)<<setw(20)<<avg<<endl; }
void main()
{ Student std[2]; // two student objects
char filename[30];
int ch,pos,p,sz=0;
cout<<"
Enter filename…";
cin>>filename;
fstream inoutfile;
inoutfile.open(filename,ios::in|ios::out);
do{cout<<"
MENU ";
cout<<"
1.Add a record
2.Display nth record
3.Exit
";
cout<<" Enter choice of operation: ";cin>>ch;
switch(ch)
{case 1: if (sz>=max)
{ cout<<"
out of bounds.."<<endl; exit(1); }
std[sz].GetData();
inoutfile.write((char*)&std[sz],sizeof(std[sz]));
sz++; // keep the count
inoutfile.close();
break;
case 2: inoutfile.seekg(0); // go to beginning
cout<<"
Enter the position of the record to be displayed : ";
cin>>p;
if(p>max)
{cout<<"
Position out of bounds";break; }
pos = (p-1) * sizeof(std) ;
inoutfile.seekg(pos);
inoutfile.read((char*)&std[p-1],sizeof(std[p-1]));
cout<<"
Details of record "<<p<<endl;
std[p-1].DisplayData();
inoutfile.close();
break;
case 3: exit(1);
}//end of switch
}while( ch>=1 && ch<4);
}//end of main
/*Output: Enter filename…Student.dat :
MENU
1.Add a record 2.Display nth record 3.Exit
Enter choice of operation: 1 Enter name: Ramesh Enter id No: 100
Enter <Maths, Science and English> Marks :90 90 90
MENU Enter choice of operation: 2 enter the position of the record to be displayed: 2
details of record 2: Name: Gautam Total: 294.00 : Average: 98.00 */
13.59.107.152