User Name Password Register
DaniWeb IT Discussion Community
All
What is DaniWeb IT Discussion Community?
You're currently browsing the C++ section within the Software Development category of DaniWeb, a massive community of 427,803 software developers, web developers, Internet marketers, and tech gurus who are all enthusiastic about making contacts, networking, and learning from each other. In fact, there are 3,777 IT professionals currently interacting right now! Registration is free, only takes a minute and lets you enjoy all of the interactive features of the site.
Please support our C++ advertiser: Programming Forums
Views: 109254 | Replies: 47
Reply
Join Date: May 2004
Posts: 251
Reputation: FireNet will become famous soon enough FireNet will become famous soon enough 
Rep Power: 6
Solved Threads: 6
FireNet's Avatar
FireNet FireNet is offline Offline
Posting Whiz in Training

fstream Tutorial

  #1  
Jun 2nd, 2004
				File I/O
                            With C++ Fstream


Intro

File handling is as simple as writing in a book, much easier to modify and
find. It's so simple people get confused with it :-). Welcome to the world of file handling.

We will use the c++ fstream classes to do our file handling. So, what is a file? A file is just a bunch of bytes stored on a hardisk. Some have a specific structure others dont. Files are used to save info so that it can be retrived later for use. [I dont think you will want to save 100 people's address in memory will you].

Types of Files

Actually there are only two. Text files and binary files. In text files data is stored as readable chars and binary file are in machine language. So if you output abc123 to a text file you will see abc123 but in a binary file you may see only a bunch of black blocks if you use notepad. The binary files are smaller in size.

Fstream.h

fstream.h provides simultaneous input and output through ifstream, ofstream and fstream.

ifstream       - open the file for input
ofstream       - open the file for output
fstream       - open the file for input/output/both

Writing to a file

Relatively very simple.

Steps:
  1. Declare an ofstream var.
  2. Open a file with it.
  3. Write to the file (there are a couple of ways.)
  4. Close it.

Eg Program 1.1

#include <fstream.h>

void main
{
	ofstream file;
	
	file.open("file.txt");		//open a file
	
	file<<"Hello file\n"<<75;		//write to it
	
	file.close();				//close it
}

Methods for Writing to a file

The fstream class is derived from the iostream classes, so you can use ofstream variables exactly how you use cout. So you can use the insertion (<<) operator and the put().

Usages:

	file<<"string\n";
	file.put('c');

Reading from a file

Almost the same.

Steps:
  1. Declare an ifstream var.
  2. Open a file with it.
  3. Read from the file(there are a couple of ways.)
  4. Close it.

Eg Program 1.2

#include <fstream.h>

void main
{
	ifstream file;
	char output[100];
	int x;
	
	file.open("file.txt");	//open a file
	
	file>>output;		//write to it
	cout<<output;		//result = Hello file
	file>>x;			
	cout<<x;			//result = 75
	
	file.close();			//close it
}

Methods for Reading a file

The fstream class is derived from the iostream classes, so you can use fstream variables how you use cin.So you can use the extraction (<<) operator and the put().

Usages:

	file>>char *;		//ie an array
	file>>char;			//single char
	file.get(char);		//single char
	file.get(char *,int);	//read a string 
	file.getline(char *,int sz);
	file.getline(char *,int sz,char eol);

Notes:

1. The file handles can be used like:

	ofstream file("fl.txt");
	ifstream file("fl.txt");

You will use the constructor for opening a file.I would not recommend using this not because it works less well or anything but in most cases it will improve code clarity and prevent errors when you are handling multiple files. If a file handle is used more than once without calling a close() in between them there will be errors. This is just provided for info sake if you need to use it in a hurry or in something small.

2. Never ever declare a fstream variable globally. It is a bad habit. If you forget to close it next time you run the program it will show access errors to the C: drive (or which ever drive you use) and you will have to restart the computer. Declare them within funtions or classes and close them when their use is over.

3. If you are doing databases or any file handling for that matter never put any file i/o into classes. It will simply complicate debugging and you may also open a single file multiple times with difffrent objects at the same time. This is definitely not what we want. Classes are only to be used when you have to minimal file i/o but still I recommend you use normal funtions.

4. ifstream stands for input stream and can only be used for input.

5. ofstream stands for output stream and can only be used for output.

6. Any variable declared with ifstream,ofstream or fstream is called a file handle.

That wraps up the simple very stuff. You will not use them much unless you are working with text files or in a small project. Now we will move on to fstream which is more flexible and will be most used. It's easy if you look at it logically.

Dynamic file access

The file streams we discussed have a limitation, they can only do input or output at a time. fstream provides us with a way to read, write randomly without having to close and reopen the file. It has great flexibility involving a bit more work with returns being ten fold. Hey, you cant have everything for free (what fun would it be if everything was handed to you).

Lets look at how a file can be opened with fstream.

Program Example 1.3

void main()
{
	fstream file;
	
	file.open("file.ext",iso::in|ios::out)
	
	//do an input or output here
	
	file.close();
}

Notice anything new? The ios::--- are attributes which define how a file should be opened.

			List of Attributes
	
ios::in 		open file for reading
ios::out		open file for writing
ios::app		open for writing,add to end of file(append).
ios::binary		Binary file
ios::nocreate	do not create the file,open only if it exists
ios::noreplace	open and create a new file if the specified file does not exist
ios::trunc		open a file and empty it.(Boom, all the data is gone,if any)
ios::ate		goes to end of file instead of the begining

Notes
  • The default mode is text mode when a file is opened
  • By default if a file does not exist,a new one is created
  • Multiple attributes can be specified at a time seperated by ...|...|...
  • All attributes start with an ios:: (as if you dint notice it,but still let me hammer it)
  • These attributes can be used with ifstream and ofstream but of course ios::in wont work with ofstream and similarly ios::out wont .............
  • File byte location start from zero (like in arrays)


Now we know how to open a file with fstream. Cool, now come read and write.

Reading and Writing with fstream

The two funtion are exactly similar in usage and simple to understand

	file.write(char *,int);		//for writing
	file.read(char *,int);		//for reading (gee...:D)

Until now we have only been able to use strings and ints to write/read. Most databases will want to store data in structures or classes. If we had to write a seperate function to split and write each member, brrr horrors. C++ goes to be very nice and provides us with a way to write entire classes or structures with little work

[/code]
struct x
{
int i;
char a;
char s[10];
}data;

file.write((char*)&data,sizeof(x));
file.read((char*)&data,sizeof(x));
[/code]

Hold on, what the heck is the char * thingy???.

That's called typecasting. Quite an interesting subject actually. It means converting one data type to another. Here it is converting struct x into a char pointer and it's address is passed to the funtion. If anybody wants to know more, well tell!

The rest is simple. You pass the size of the structure which can be found out by using sizeof();

Eg:

cout<<"\nInt:"<<sizeof(int);
cout<<"\nFloat:"<<sizeof(float);
cout<<"\nChar:"<<sizeof(char);

Now instead of going more yack yack I show you an example which should explain a lot more. Sigh "A picture is worth a thousand word, source is worth a million bytes"

Example Program 1.4

#include <fstream.h>

struct  contact
{
	char name[10];
	int age;
}

struct address
{
	char city[10];
	char country[10];
}

class DtbRec
{
	private:
	contact cnt;
	address adr;
	
	public:
	void getdata();
	void dispdata();
};

/*
   I will give you a bit of work, make the funtions getdata() and dispdata()
   It's easy and not worth for me to bother with now :-}
*/
   
void DtbRec::getdata() //get user input
{

}

void DtbRec::dispdata()  //display to screen
{

}

//This program is not tested, have fun fixing errors, if any
//I am a taos programmer so dont expect anything major
//Typing mistakes are not errors
//This was done off the cuff and not even compiled once

void main()
{
	DtbRec xRec;		//temp rec
	fstream fl_h;	//file handle
	char ch;
	int num;
	
	fl_h.open("database.dtb",ios::in|ios::out|ios::binary);
	
	do
	{
		cout<<"\n\nFstream Dtb\n"
		      <<"\n1.Add records"
		      <<"\n2.View records"
		      <<"\n3.Modify records"
		      <<"\n4.Exit"
		      
		      <<"\n\tEnter Choice:";
		      
		cin>>ch;
		
		if(ch == '1')	//we are dealing with chars not ints
		{
			//Adding a rec
			
			fl_h.seekp(0,ios::end);	//will disscuss this later,this sets the file write pointer to
							//the end of a file.
			xRec.getdata();		//Get some data from the user
			
			fl_h.write((char*)&xRec,sizeof(DtbRec);
			
		}
		else if(ch == '2')
		{
			//View recs
			
			fl_h.seekg(0,ios::beg);	//will disscuss this later,this sets the file read pointer to the 
							//begining of a file.
			num = 0;
			while(!fl_h.eof())		//will disscuss this later,it check if the file's end has been reached
			{
				n++;
				fl_h.read((char*)&xRec,sizeof(DtbRec);
				
				cout<<"\nRecord No["<<num<<"]\n";
				xRec.dispdata();	//Show the user all the data present
			}
		}
		else if(ch == '3')
		{
			//Modify me colors ;-)
			
			cout<<"Enter the record no(starts at 0):";
			cin>>num;
			
			fl_h.seekg(num*sizeof(DtbRec),ios::beg);	//move the read pointer to where the rec is
			fl_h.read((char*)&xRec,sizeof(DtbRec);	//read it
			xRec.dispdata();					//Show the info
			xRec.getdata();					//Let the user change the info
			
			fl_h.seekp(num*sizeof(DtbRec),ios::beg);	//move the write ponter this time
			fl_h.write((char*)&xRec,sizeof(DtbRec);	//overwrite with new info
			
			//yahoo,modification done.I have seen too many people who just
			//cant get modification .It's so simiple I just cant get why they just cant
			//get it ;-)
		}
	}
	while(ch != '4');
	
	fl_h.close();		//close the file
	cout<<"\nEnd of Program";
}

Got more doubts now than what was cleared? Good, doubts are the first step towards knowledge. (If you happen to be of an opinion that a teacher should explain everything, sorry it's just not my style. I want thinking students not tape recorders)

Note:
  • Records start at byte zero. I said this once and I will say it again.(Dont forget user friendlyness though.)
  • read() and write() can be used to write both classes and structures to the file in the same way.
  • Always know where you are before you start reading or writing to a file or move the pointer to the area of work.
  • The read pointer and write pointer are separate. So move the correct pointer if you want fstream to work.
  • Always close the file when it's use is over.
  • Always perform checks when necessary or appropriate. fstream has a number of buit-in ones for you :-)
  • Never open a new file with a file handle without calling close().
  • Remember, with structs and classes their size is always fixed so finding the exact location of a record can be done mathematically.


------------------------- PART II -------------------------

Random File Access


With fstream we work with 2 file pointers, read and write. By moving these pointers we go access any part of the file at random. See below:

	Reading
	1.seekg();	//move the read pointer in bytes
	2.tellg();	//returns where the read pointer is in bytes
	
	Writing
	1.seekp();	//move the write pointer in bytes
	2.tellp();	//returns where the write pointer is in bytes


Both tellp() and tellg() don't take any parameters but return where the pointer location in bytes.

Eg.
	int rp = file.tellg();
	int wp = file.tellp();


The seek pointers take 2 parameters

Eg.
	file.seekg(0,ios::beg);


	
		List of seek attributes
	
	ios::beg		move from the beginning of the file
	ios::end		move from the end of the file
	ios::cur		move from current location of the file


Note:
  • ios::beg is default. I recommend you still pass it where ever you use it.
  • Negative numbers can be used with ios::cur & ios::end.(not ios::beg figure it out)

					Part II			
				Databases & Security
			(Based on a true story of a database)

Intro


This is another area people find difficulty. I figured it out myself without any help what so ever. I also learned file handling a year before my classmates by looking at an elder's text which contained only vague descriptions so I guess my eagerness to learn had something
to do with it. I have always loved computers and programming. I fell in love with QBasic the moment I saw it. C++ stole my heart then. Ah, programming is a part of my soul.

And even when I got my own text book nothing what so ever was mentioned about random file access except a short and vague description about the 2 functions and the options. There was no reference what so ever about locating individual records. I can't guess why! Reminds me of a saying "when old, one forgets how it is to be young". That maybe a cause :D.

[oh, this reminds me, almost every comp guy/gal I know works late at night. I do too when I don't have much time in the mornings. We should stop this. Never work in the dark without enough light, nor stay up too late. If your eyes feel slightly sleepy,SLEEP. No more than 1:30 AM at the most, I am thankful I been able to do most of this]

Locating Individual Records

Problem area. Let start at the beginnings. Ever seen a graph paper ?.It has a lot of tiny, small, medium and large sized squares. Also each is being made from the tiniest square. What that got a do with files? Well when you use databases you will almost always use structures and they are always the same size (in that particular database). That means like in the program in Part I all the records are with that one class and when you write it to a file it will still be the same size even if you filled it or not. It's like your water bottle. Whether it's full, half or even empty it will always
take up the same space in your bag. Get it?

How do you find the size of any data type ?Easy.

Size_Of_Data_Type = sizeof(Data_Type); //sizeof is a reserved keyword in C++.

Ok, how will that help us find a record? Well all records are of the same size, they start at zero. They can be thought of as an array too and the concept is similar to how you use normal pointers.

Eg. A struct is 20 bytes in size. The first rec starts at byte zero, the second at byte 20, the next at byte 40 ...... and so on

Eg. Program 2.1

	file.seekg( Rec_no * sizeof(Data_Type),ios::beg);
	file.read((char*)&rec_var,sizeof(Data_Type));
	
	file.seekp( Rec_no * sizeof(Data_Type),ios::beg);
	file.write((char*)&rec_var,sizeof(Data_Type));


Simple as that.

Note:
  • This can be use with ios::beg,ios::cur and ios::end
  • When read() or write() is called the appropriate pointer is moved automatically to the next record or rather by a number of bytes as passed to it(that's the sizeof(Data_Type))

I think now you get random access. How about finding the total number of records in a database?

Eg. Program 2.2

	file.seekg(0,ios::end);		//move to the end of the file
	
int fl_sz = file.tellg();		//tell me where you are, partner( pointer ) !
	int total_no_rec = fl_sz/sizeof(Data_Type);
	
	file.seekg(0,ios::beg);		//move to the beg of the file
	
	cout<<"There are "<<total_no_rec<<" (s) in this database ";


We divide the total file size by the size of the structure to find the number of record. Simple maths eh?

That's it you have full knowledge of how to handle fstream. Now all you need is creativity, so use it. I won't tell you all, so think. Knowledge can be gained from others but wisdom only from yourself (and from God).

Ah, I love this. Here is some work for you.
  1. Re-write the example program to include random reading, writing, and modification on multiple databases. [Put in error checks and don't allow the user to read or modify a rec which does not exist]
  2. Find a way to write a whole single dimensional array of a struct to a file with just one write statement. [No hints, re-read this paper if you have to]
  3. Deletion. Add a way to allow a person to delete an existing record.
  4. [One way to do it, copy all the records except the one to be deleted to another temp file, open the database with ios::trunc and copy the records from the other temp file.]

Error Checking

These are some funtions that help to keep track of errors in your database if any

				Error Funtions
	
	good()		returns true if the file has been opened without problems
	bad()			returns true if there were errors when opening the file
	eof()			returns true if the end of the file has been reached


All are member funtions and are used as file_handle.errror_funtion()

Eg.

	char ch;
	ifstream file("kool.cpp",ios::in|ios::out);
	
	if(file.good()) cout<<"The file has been opened without problems;
	else cout<<"An Error has happend on opening the file;	
	
	while(!file.eof())
	{
		file>>ch;
		cout<<ch;
	}


You should have understood what those funtions are for. Implement them when you do you file handling. good() should be called after opening a file to see it has been opened properly. bad() is the opposite of good().

Encryption

Aha, any decent database program must encrypt its files. Just open up any of the files from the example programs with notepad and you will be able to see the text. We definitely don't want people to see that.

With encryption you can scramble the text so people can read it. Now there are a lot of encryption schemes and a lot of other methods for protecting data. I will just show you a couple of methods.

Binary Shift

The simplest of all. In this you increase or decrease a char by a number.

void b_shif(char *s,int n)
{
	for(int i=0;s[i]!=0;i++)
	{
		s[i] += n;
	}
}

XOR

Another type of encryption. Exclusive-OR encryption, is almost unbreakable through brute force methods. It is susceptible to patterns, but this weakness can be avoided through first compressing
the file (so as to remove patterns). This encryption while extremely simple, is nearly unbreakable.

int xor(char *string, char *key)
{
	int l=0;
	for(int x=0; string[x]!='\0'; x++)
	{		
		string[x]=string[x]^key[l];
		l++;
		if(l>=strlen(key)) l=0;
	}
	return 0;
}

Encrypt an entire structure

void struct_enc_xor(char *str,char *key,int sz)
{
	int l=0;
	for(int x=0; str[x]!='\0'; x++)
	{		
		str[x]=str[x]^key[l];
		l++;
		if(l>=strlen(key)) l=0;
	}
	return 0;
}

Use it exactly how you used read().

Eg.
struct_enc_xor((char*)&cRec,"password",sizeof(DtbRec));

Exit

Encryption is a very interesting topic. A lot of research has gone into it. If you are interested there are lot of pages on the web which describe encryption and various schemes. Then there is stenography,
the art of hiding info in any file like text within a bitmap or an mp3. Have fun researching.
Last edited by happygeek : Nov 12th, 2006 at 10:40 am. Reason: Formatting, spelling etc
See what you can, remember what you need

Fourzon | Earn via Coding
AddThis Social Bookmark Button
Reply With Quote  
Join Date: May 2004
Posts: 251
Reputation: FireNet will become famous soon enough FireNet will become famous soon enough 
Rep Power: 6
Solved Threads: 6
FireNet's Avatar
FireNet FireNet is offline Offline
Posting Whiz in Training

Re: fstream Tutorial

  #2  
Jun 7th, 2004
Now here's a printer friendly version(has a few fixes to part I)

http://www.polarhome.com:793/~xlock/txt/fstream.txt
See what you can, remember what you need

Fourzon | Earn via Coding
Reply With Quote  
Join Date: Feb 2002
Location: Lawn Guylen, NY
Posts: 10,949
Reputation: cscgal is just really nice cscgal is just really nice cscgal is just really nice cscgal is just really nice cscgal is just really nice 
Rep Power: 32
Solved Threads: 116
Admin
Staff Writer
cscgal's Avatar
cscgal cscgal is online now Online
The Queen of DaniWeb

Re: fstream Tutorial

  #3  
Jun 7th, 2004
Cool. In addition, DaniWeb users can always use the Thread Tools dropdown and then select Printable Version for any thread
Reply With Quote  
Join Date: Aug 2004
Location: Malaysia
Posts: 19
Reputation: Pikachu is an unknown quantity at this point 
Rep Power: 5
Solved Threads: 0
Pikachu's Avatar
Pikachu Pikachu is offline Offline
Newbie Poster

Re: fstream Tutorial

  #4  
Aug 10th, 2004
Hello!
I have a little question. Lets say, I have a file called word.txt and it contains 100 over words.
How do I add a new word and SAVING it so I can use this word from this file in future?

Thanks
Reply With Quote  
Join Date: May 2004
Posts: 251
Reputation: FireNet will become famous soon enough FireNet will become famous soon enough 
Rep Power: 6
Solved Threads: 6
FireNet's Avatar
FireNet FireNet is offline Offline
Posting Whiz in Training

Re: fstream Tutorial

  #5  
Aug 21st, 2004
Quite simple really,just open word.txt with ios::app (append) added to the options when opening the file.That will automaticaly put the file pointer to the end of the file and you can just write to it normally.

Another way is to open the file and use filehandle.seekp(0,ios::end); to move the pointer to the end of the file and then write the output you want to the file and it will still be at the end.

Checks the tut for the list of options,I covered them there.

Btw,then close the file when you exit or are finished with using it.There you go a new word was added to the file.
See what you can, remember what you need

Fourzon | Earn via Coding
Reply With Quote  
Join Date: May 2004
Posts: 251
Reputation: FireNet will become famous soon enough FireNet will become famous soon enough 
Rep Power: 6
Solved Threads: 6
FireNet's Avatar
FireNet FireNet is offline Offline
Posting Whiz in Training

Re: fstream Tutorial

  #6  
Sep 2nd, 2004
A little update.My site URL is now:
http://xlock.hostcubix.com/
See what you can, remember what you need

Fourzon | Earn via Coding
Reply With Quote  
Join Date: Sep 2004
Posts: 2
Reputation: Jubulani is an unknown quantity at this point 
Rep Power: 0
Solved Threads: 0
Jubulani Jubulani is offline Offline
Newbie Poster

Re: fstream Tutorial

  #7  
Sep 7th, 2004
Interesting tutorial, however I did notice a few errors here and there.
if you output abc123 to a
text file you will see abc123 but in a binary file you may see only a bunch of black
blocks if you use notepad
I just tested this, and its not true. If you output "abc123" to a binary file, you will see "abc123" when you open that file in notepad (or any text editor). The difference between binary mode and text mode is that text mode replaces '\n' with something appropriate for the operating system you are using. Different OS's store linebreaks differently: IIRC Windows uses "\n\r" pairs, unix uses '\n' and macs use '\r'. Text mode will translate between these automatically for you, binary mode will not.

If a file handle is used
more than once without calling a close() in between them there will be errors
If you open an ofstream object with a file name, and write output to it, then call open() on the same file stream without closing it, there will be no errors. The call to open() will close the file you were writing to and just open another file. Similarly:
If you forget to close it [the fstream object]
next time you run the program it will show access errors to the C: drive (or which ever drive
you use) and you will have to restart the computer.
The destuctor of an fstream object will close any file handles for you. The last program I made left an open file handle at the end of the program. There was no problem with this, as when the destructor of the ofstream object was called, it closed the file handle automatically. Destructors are guaranteed to be called for all objects at the end of their life (for a global object at the end of the program) so there is no problem leaving file handles open. The only possible problem with this is if your program causes a seg fault or something similar, and the OS has to close it unexpectedly. In that case you have more problems than open file handles though. I do so love the fstream library. Its so hard to f*ck thinks up with it.

It was a very interesting tutorial though. You did a lot with fstream that I wouldn't have thought of.
Reply With Quote  
Join Date: May 2004
Posts: 251
Reputation: FireNet will become famous soon enough FireNet will become famous soon enough 
Rep Power: 6
Solved Threads: 6
FireNet's Avatar
FireNet FireNet is offline Offline
Posting Whiz in Training

Re: fstream Tutorial

  #8  
Sep 8th, 2004
True enough,about certain char being translated in the text mode.But let me remind that file<<"abc123" is a string.Try doing file<<"abc"<<123<<(char)123;

See what happens, one forgets and assumes a bit somethimes.

If you open an ofstream object with a file name, and write output to it, then call open() on the same file stream without closing it, there will be no errors. The call to open() will close the file you were writing to and just open another file. Similarly:

Try doing that with the fstream object.Also if an fstream object is declared in the global scope and it's not closed when you run the program again some access errors might be shown. A lot of my friends had this problem when they did their projects.Never declare anything global unless it's necessary.

This may not be true on diffrent compilers (or even the same one's diffrent versions).That could have happened due to a lot of reasons.But it a good practice to alway close a file handle before you exit .I just said something which might possibly happen, .

I love the fstreams too.Thanks so much Jubulani.
See what you can, remember what you need

Fourzon | Earn via Coding
Reply With Quote  
Join Date: Sep 2004
Posts: 2
Reputation: Jubulani is an unknown quantity at this point 
Rep Power: 0
Solved Threads: 0
Jubulani Jubulani is offline Offline
Newbie Poster

Re: fstream Tutorial

  #9  
Sep 10th, 2004
Oops, my mistake. Calling 'open()' on an open file stream does cause errors. Sorry about that. And, true, always better safe than sorry.

Reply With Quote  
Join Date: May 2004
Posts: 251
Reputation: FireNet will become famous soon enough FireNet will become famous soon enough 
Rep Power: 6
Solved Threads: 6
FireNet's Avatar
FireNet FireNet is offline Offline
Posting Whiz in Training

Re: fstream Tutorial

  #10  
Sep 11th, 2004
Yea, prevention is better than cure
See what you can, remember what you need

Fourzon | Earn via Coding
Reply With Quote  
Reply

Only community members can participate in forum threads. You must register or log in to contribute.

DaniWeb C++ Marketplace
Currently Active Users Viewing This Thread: 4 (0 members and 4 guests)

 

Thread Tools Display Modes

Similar Threads
Other Threads in the C++ Forum

All times are GMT -4. The time now is 2:16 pm.
Forum system based on vBulletin Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
©2003 - 2008 DaniWeb® LLC