









Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
A program is a precise sequence of steps to solve a particular problem. This course includes basic programming structure like loops, operator, memory allocation, reference, pointers etc. It teaches how to be a good programmer. This lecture handout is about: Random, Access, Files, Sequential, Position, Setting, Function, Data, Insertion, Reverse, Order, Sample, Program, Handling, Streams
Typology: Study notes
1 / 17
This page cannot be seen from the preview
Don't miss anything!










Sequential Access Files (Continued) Last Lecture Reviewed Random Access Files
In the last lecture, we discussed little bit about Sequential Access Files under the topic of File Handling. Sequential Access Files are simple character files. What does the concept of sequential access mean? While working with the sequential access files, we write in a sequence, not in a random manner. A similar method is adopted while reading such a file.
In today’s lecture, we will discuss both the topics of File Handling and Random Access Files.
Before going ahead, it is better to recap of File Handling discussed in the previous lecture. Let’s refresh the functions or properties of File streams in our minds.
Last Lecture Reviewed
It is so far clear to all of us that we use open () function to open files. Similarly, to close a file close () function is used. open () has some parameters in its parenthesis as open (filename, mode) but close () brackets remain empty as it does not have any parameter. A file can be opened for reading by using the open () function. It can also be opened for writing with the help of the same open () function. But different argument value will be needed for this purpose. If we are opening for reading with ifstream (Input File Stream), a simple provision of the filename is sufficient enough, as the default mode is for reading or input. We can also provide an additional argument like open ("filename", ios::in). But this is not mandatory due to the default behavior of ifstream. However, for ofstream (Output File Stream), we have several alternatives. If we open a file for writing, there is default mode available to destroy (delete) the previous contents of the file, therefore, we have to be careful here. On the other hand, if we don’t want to destroy the contents, we can open the file in append mode (ios::app). ios:trunc value causes the contents of the preexisting file by the same name to be destroyed and the file is truncated to 0 length.
/* Following program writes an integer, a floating-point value, and a character to a file called ‘test’ */
#include <iostream.h> #include <fstream.h>
main(void) { ofstream out(“test”); //Open in default output mode
if ( !out ) { cout << “Cannot open file”; return 1; } out << 100 << “ “ << 123.12 << “a”;
out.close();
return 0; }
If you want to open a file for writing at random positions forward and backward, the qualifier used is ios:ate. In this case, the file is at first opened and positioned at the end. After that, anything written to the file is appended
docsity.com
if (!fromFile) { cout << "unable to open ’thisFile’ for input"; } ofstream toFile ("thatFile"); if ( !toFile ) { cout << "unable to open ’thatFile’ for output"; } char c ; while (toFile && fromFile.get(c)) { toFile.put(c); }
This code:
It is, of course, undesirable to copy a file this way, one character at a time. This code is provided just as an example of using fstreams.
We have also discussed a function getline () , used to read (get) one line at a time. You have to provide how many characters to read and what is the delimiter. Because this function treats the lines as character strings. If you use it to read 10 characters, it will read 9 characters from the line and add null character (‘\0’) at the end itself.
You are required to experiment with these functions in order to understand them completely.
docsity.com
Random Access Files
Now we will discuss how to access files randomly, forward and backward. Before moving forward or backward within a file, one important factor is the current position inside the file. Therefore, we must understand that there is a concept of file position (or position inside a file) i.e. a pointer into the file. While reading from and writing into a file, we should be very clear from where (which location inside the file) our process of reading or writing will start. To determine this file pointer position inside a file, we have two functions tellg() and tellp().
Position in a File Let’s say we have opened a file stream myfile for reading (getting), myfile.tellg () gives us the current get position of the file pointer. It returns a whole number of type long , which is the position of the next character to be read from that file. Similarly, tellp () function is used to determine the next position to write a character while writing into a file. It also returns a long number. For example, given an fstream object aFile: Streampos original = aFile.tellp(); //save current position aFile.seekp(0, ios::end); //reposition to end of file aFile << x; //write a value to file aFile.seekp(original); //return to original position
So tellg () and tellp () are the two very useful functions while reading from or writing into the files at some certain positions.
Setting the Position The next thing to learn is how can we position into a file or in other words how can we move forward and backward within a file. Suppose we want to open a file and start reading from 100th character. For this, we use seekg () and seekp () functions. Here seekg () takes us to a certain position to start reading from while seekp () leads to a position to write into. These functions seekg () and seekp () requires an argument of type long to let them how many bytes to move forward or backward. Whether we want to move from the beginning of a file, current position or the end of the file, this move forward or backward operation, is always relative to some position.. From the end of the file, we can only move in the backward direction. By using positive value, we tell these functions to move in the forward direction .Likewise, we intend to move in the backward direction by providing a negative number. By writing: aFile. seekg (10L, ios::beg) We are asking to move 10 bytes forward from the begining of the file.
docsity.com
have to utilize at least one block of disk space. The remaining space of the block except first 53 bytes, goes waste. Therefore, normally the size of the file (which is in blocks) is greater than the actual data length of the file. When this file will be read from the disk, the whole chunk (block) is read instead of the actual data length. By using seekg () function, we can know the actual data length of the file. For that purpose, we will open the file and go to the end of the file by asking the seekg () function to move 0 bytes from the end of the file as: seekg (0, ios::end). Afterwards, (as we are on end of file position), we will call tellg () to give the current position in long number. This number is the actual data bytes inside the file. We used seekg () and tellg () functions combination to determine the actual data length of a file.
/* This is a sample program to determine the length of a file. The program accepts the name of the file as a command-line argument. */
#include <fstream.h> #include <stdlib.h>
ifstream inFile; ofstream outFile;
main(int argc, char **argv) {
inFile.open(argv[1]);
if(!inFile) { cout << "Error opening file in input mode"<< endl; }
/* Determine file length opening it for input */ inFile.seekg(0, ios::end); //Go to the end of the file long inSize = inFile.tellg(); //Get the file pointer position cout << "The length of the file (inFile) is: " << inSize; inFile.close();
/* Determine file length opening it for output */ outFile.open(argv[1], ios::app); if(!outFile) { cout << "Error opening file in append mode"<< endl; } outFile.seekp(0, ios::end); long outSize = outFile.tellp(); cout << "\nThe length of the file (outFile) is: " << outSize; outFile.close();
docsity.com
Run this program to see its output that shows different results for both input and output modes. Discuss it on discussion board.
Data Insertion in the Middle of a File
The question arises why to talk about seekg () and tellg () functions before proceeding to our original topic of random access to files. This can be well- understood from the following example. Let’s suppose, we have written a file containing names, addresses and dates of birth of all students of our class. There is a record of a student, who is from Sukkur. After sometime, we come to know that the same student has moved to Rawalpindi. So we need to update his record. But that record is lying somewhere in the middle of the file. How can we update it? We can search Sukkur using seekg () and tellg () functions. After finding it, can we update the word sukkur with the Rawalpindi. No. It is just due to the fact that Rawalpindi is longer in length than the word Sukkur and the subsequent data of Data of Birth of the student will be overwritten. So the structure of the file is disturbed and as a result your data file will be corrupted. This is one of the issues to be taken care of while writing in the middle of a sequential file.
Let’s think again what is the actual problem. The file is lying on the disk. We started reading that file and reached somewhere in the middle of the file to replace data at that position. But the data we are going to replace is shorter in length as compared to the new one. Consider how is this on the disk. We need some kind of mechanism to cut the disk, slide it further to make some space to insert the data into. But this is not practically possible. In the times of COBOL, the Merge Method was employed to insert data into the middle of the file. The logic of Merge method is to copy all the data into a new file starting from beginning of the file to the location where we want to insert data. So its algorithm is:
This is the only way of inserting the data in the middle of a sequential file. After this process, you may delete the old file and rename the new file with the same name as that of the old file. This was done in the past. But now nowadays, it is used some time when the size of the data is not huge. But obviously, it is very wasteful as it takes lot of time and space in case of
docsity.com
Lets see how can these tricks work
As discussed in the example of data updation within a file, what can happen if we know the exact things and want to replace a q character in a sentence? We should think of the logic first as it has always to be with logic and analysis that what would be algorithm for a problem. Lets say we wrote a sentence This is an apple in a file and want to change it to This is a sample. The length of both the sentences is same. /* This program firstly writes a string into a file and then replaces its partially. It demonstrates the use of seekp(), tellp() and write() functions. */
#include
int main () {
docsity.com
long pos; ofstream outfile; outfile.open ("test.txt"); // Open the file outfile.write ("This is an apple",16); // Write the string in the file pos = outfile.tellp(); // Get the File pointer position outfile.seekp (pos-7); // Move 7 positions backward outfile.write (" sam",4); // Write 4 chars in the current position outfile.close(); // Close the file return 0; }
Efficient Way of Reading and Writing Files
Let’s consider another example. We know how to read a file character by character, write into another file or on the screen. If we want to write into a file after reading another file, there are already enough tools to get (read) one character from a file and put (write) into the other one. We can use inputFile.getc () to get a character and outputFile.putc () to write a character into a file. As mentioned earlier, there is very inefficient way of doing things. We also know that for reading and writing to disk, processing in chunks is more efficient. Can we handle more data than a single byte or a single line? The answer is yes. We can use read () and write () functions for this purpose. These functions are binary functions and provided as a part of the stream functions. The term binary means that they read and write in binary mode , not in characters. We tell a location in memory to read () function to write the read data and with the number of bytes to read or write. Usually, read(arrayname, number of bytes) e.g. read(a, 10).
Now depending on our computer’s memory, we can have a very large data in it. It may be 64K.
You are required to write two programs:
One program will be used to get to read from a file and put to write into the other file. Prepare a simple character file using notepad or any other editor of your choice. Put some data inside and expand the size of the data in the file by using the copy-paste functions. A program can also be written to make this big-sized data file. The file size should be more than 40K preferably. Read this file using getc () and write it another file using putc (). Try to note down the time taken by the program. Explore the time () function and find out how to use it in your program to note the processing time. Write another program to do the same operation of copying using read and write functions. How to do it?
docsity.com
Open the input file. One of the ways of reading the files is to go to its end and start reading in the reverse direction byte by byte. We have already discussed , how to go to the end the file using seekg (0, ios:end). By now, you will be aware that while reading, the next byte is read in the forward direction. With the use of seekg (0, ios:end) , we are already at end of the file. Therefore, if want to read a byte here it will not work. To read a byte, we should position file pointer one byte before the byte we are going to read. So we don’t want to go to the end but one byte before it by using: aFile.seekg (-1, ios::end);
We also know that whenever we read a byte, the file pointer automatically moves one byte forward so that it is ready to read the next byte. But in our case, after positioning, the file pointer 1 byte before the end of file and reading 1 byte has caused the file pointer to move automatically to the end of file byte and there is no further data of this file to read. What we need to do now to read the next byte (second last byte of input file) in reverse order is to move 2 positions from the end of file: aFile.seekg (-2, ios::end);
Generically, this can also be said as moving two positions back from the current position of the file pointer. It will be ready to read the next character. This is little bit tricky but interesting. So the loop to process the whole file will run in the same fashion that after initially positioning file pointer at second last byte, it will keep on moving two positions back to read the next byte until beginning of the input file is reached. We need to determine the beginning of the file to end the process properly. You are required to workout and complete this exercise, snippet of the program is given below: aFile.seekg(-1L, ios::end); while( aFile ) { cout << aFile.tellg() << endl; aFile.get(c); aFile.put(c); aFile.seekg(-2L,ios::cur) ; }
Remember, generally, if statement is very expensive computation-wise. It takes several clock cycles. Sequential reading is fairly fast but a little bit tedious. To reach to 100 th^ location, you have to read in sequence one by one. But if you use seekg () function to go to 100th^ location, it is very fast as compared to the sequential reading.
As discussed, in terms of speed while doing file handling are read () and write () functions. The thing needed to be taken care of while using these functions is that you should have enough space in memory available. We have discussed very simple example of read () and write () functions earlier
. But it is more complex as you see in your text books. Don’t get confused, you remember we used array. Array name is a pointer to the beginning of
docsity.com
the array. Basically, the read () requires the starting address in memory where to write the read information and then it requires the number of bytes to read. Generally, we avoid using magic numbers in our program. Let’s say we want to write an int into a file, the better way is to use the sizeof () function that can write an integer itself without specifying number of bytes. So our statement will be like: aFile.write (&i, sizeof (i));
What benefits one can get out of this approach?. We don’t need to know the internal representation of a type as same code will be independent of any particular compiler and portable to other systems with different internal representations. You are required to write little programs and play with this function by passing different types of variables to this function to see their sizes. One can actually know that how many bytes take the char type variable, int type variable or a double or a float type variable. You are required to write a program to write integers into a file using the write () function. Open a file and by running a loop from 0 to 99, write integer counter into the file. After writing it, open the file in notepad. See if you can find integers inside of it. You will find something totally different. Try to figure out what has happened. The clue lies in the fact that this was a binary write. It is more like the internal representation of the integers not what you see on the screen. You are required to play with it and experiment it by writing programs.
It is mandatory to try out the above example. Also experiment the use of read () function to read the above written file of integers and print out the integers on the screen. Can you see correct output on the screen? Secondly, change the loop counter to start from 100 to 199, write it using write () function and print it on the screen after reading it into an integer variable using read () function. Does that work now? Think about it and discuss it on discussion board.
Sample Program 1
/* This is a sample program to demonstrate the use of open(), close(), seekg(), get() functions and streams. It expects a file named my-File.txt in the current directory having some data strings inside it. */
#include <fstream.h> #include <stdlib.h>
/* Declare the stream objects */ ifstream inFile; ofstream scrn, prnt;
main() {
docsity.com
Sample Program 2
/* This sample code demostrates the use of fstream and seekg() function. It will create a file named my-File.txt write alphabets into it, destroys the previous contents */
#include <fstream.h>
fstream rFile; // Declare the stream object main() { char rChar; /* Opened the file in both input and output modes / rFile.open("my-File.txt", ios::in || ios::out); if(!rFile) { cout << "error opening file"<< endl; } / Run the loop for whole alphabets */ for ( rChar ='A'; rChar <='Z'; rChar++) { rFile << rChar; // Insert the character in the file } rFile.seekg(8l, ios::beg); // Seek the beginning and move 8 bytes forward rFile >>rChar; // Take out the character from the file cout << "the 8th character is " << rChar ;
rFile.seekg(-16l, ios::end); // Seek the end and move 16 positions backword rFile >>rChar; // Take out the character at the current position cout << "the 16th character from the end is " << rChar ;
rFile.close(); // Close the file }
Exercises
docsity.com
reverse org-file.txt rev-file.txt
Use the algorithm already discussed in this lecture.
Tips
Be careful for file mode before opening and performing any operation on a file. The concept of File Pointer is essential in order to move to the desired location in a file. tellg() , seekg() , tellp() and seekp() functions are used for random movement (backward and forward) in a file. There are some restrictions (conditions) on a file to access it randomly. Like its structure and record size should be fixed. Ability to move backward and forward at random positions has given significance performance to the applications. Binary files (binary data) can not be viewed properly inside a text editor because text editors are character based.
docsity.com