Tuesday, December 24, 2013

Chapter 10: Files in C



10.1 Introduction
Many applications require the information to be written or read from an auxiliary memory device. Such information is stored on the memory device in the form of a data file. Thus, data files allow us to store information permanently, and to access and alter that information whenever necessary.
In C, an extensive set of library functions are available for creating and processing these files. There are two different types of data files:
            1. Stream-oriented (or standard) data files
            2. System-oriented (or low-level) data files
Stream-oriented data files are divided into two categories:
Text Files:
   -consists of consecutive characters
   -these characters can be interpreted as individual data items, or as components of strings or numbers
Unformatted data files:
            -organizes data into blocks containing contiguous bytes of information
            -these blocks represents more complex data structures, such as array and structures.
System-oriented data files:
            -are more closely related to the computer's operating system
            -more complicated to work with
            -A seperate set of procedures, library functions are require to process these files
Here, we will discuss only about Stream-oriented data files.
The C file system is composed of several interrelated functions. The most common of these are shown below. They require the header file stdio.h to be included.
Name                                                  Function
fopen()                                                 Opens a file
fclose()                                                 Closes a file
putc()                                                   Writes a character to a file
fputc()                                                  Same as putc()
getc()                                                   Reads a character from a file
fgetc()                                                  Same as getc()
fgets()                                                   Seads a string from a file
fputs()                                                  Writes a string from a file
fseek()                                                  Seeks to a specified byte in a file
ftell()                                                    Returns the current file position
fprintf()                                                 Is to a file what printf() is to the console
fscanf()                                                Is to a file what scanf() is to the console
feof()                                                    Return true if end-of-file is reached
ferror()                                                 Return true if an error has occured
rewind()                                               Resets the file position indicator to the beginning
remove()                                              Erases a file
fflush()                                                  Flushes a file

                        Table: Commonly used C file system functions
The FILE Pointer
The FILE pointer is the common thread that unites the C I/O system. A file pointer is a pointer to a structure of type FILE. It points the information that defines various things about the file, including its name, status, and the current position of the file.
Inorder to read or write files, your program needs to use file pointers.
                        FILE *fp;

Opening a file
Before we can write a file to disk, or read it, we must open it. Opening a file establishes an understanding between our program and the operating system about which file we are going to access and how we are going to do it. We provide the operating system with the name of a file and other information like whether we plan to read or write to it.
Opening a file start with the declaration of variable of type pointer to a file in the statement as:
            FILE *fptr;
Then we open the file with the statement
            fptr=fopen("name.txt","w");
Thus, fopen() function takes two arguments. The first argument is the name of file to be opened and the second argument is the mode in which file has to be opened.

The table below shows the legal values for mode.

Mode                           Meaning
r                                        Opens a text file for reading. The file must exist.
w                                       Create a text file for writing. If the file exists, its contents will be   written over. If does not exist it will be created.                          
a                                  Append to a text file. Data will be added to the enf of an existing file, or a new file will be created
r+                                     Opens a text file for both reading and writing. The file must already exist.
w+                                 Opens a text file for both reading and writing. If the file exists its contents are written over.
a+                                   Opens a text file for both reading and appending. If file does not exist it will be created.
rb                                      Opens a binary file for reading.
wb                                    Create a binary file for writing
ab                                     Append to a binary file
r+b                                   Opens a binary file for read/write
w+b                                 Create a binary file for read/write
a+b                                   Append or create a binary file for read/write.

            Table: The legal values for mode
Note: Strings like "r+b" may also be represented as "rb+"


Closing a file
The fclose() function closes a stream that was opened by a call to fopen(). The fclose() function has this prototype:
            int fclose(FILE *fp);
Where, fp is the file pointer returned by the call to fopen(). A return value of zero signifies a successful close operation. The function returns EOF if an error occurs. You can use the standard function ferror() to determine and report any problems. Generally, fclose() will fail only when a disk has been permanently removed from the drive or there is no more space in the disk.
The opened file is closed with the following statement:
            fclose(fp);

10.2 Character input/Output functions in file

getc(), putc(), fgetc(), and fputc()  are charcter input output functions. As a practical use of these character input output functions we can read line of text in lowercase and convert it to uppercase, as demonstrated in the following example.

use of getc( ) and putc( ) functions to read a line of text in lowercase and store in data file after converting it to uppercase.
Example 1
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<ctype.h>
main()
{
char ch;
FILE *fp;
fp=fopen("file1.txt","a+");
if(fp==NULL)
{
printf("cannot open file");
fclose(fp);
exit(1);
}
do
{
ch=toupper(getchar());
putc(ch,fp);
}while(ch!='\n');
clrscr();
rewind(fp);
while((ch=getc(fp))!=EOF)
printf("%c",ch);
fclose(fp);
getch();
}

Coping contents of one file into another. This program takes the contents of a text file and copies them into another text file character by character


Example 2
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
main()
{
char ch;
FILE *fs,*ft;
fs=fopen("file1.txt","r");
if(fs==NULL)
{
printf("can not open source file\n");
exit(1);
}
ft=fopen("file2.txt","w");
if(ft==NULL)
{
printf("Cannot open target file");
fclose(ft);
exit(1);
}
while((ch=fgetc(fs))!=EOF)
fputc(ch,ft);
fclose(fs);
fclose(ft);
getch();
}
In this program file1.txt is a source file which is opened in read mode and file2.txt is a destination file which is opened in write mode.

Using feof() function
The function feof() determines when the end of the file has been encountered. The feof() function has this prototype:
            int feof(FILE *fp);
feof() returns true(1) if the end of the file has been reached; otherwise, it returns 0.
e.g.
while(!feof(fp))
ch=getc(fp);
The operation of feof() is illustrated in the Example 3.

10.3 String input/output function in file
Reading or writing strings of characters from and to files is easy as reading and writing individual characters. fputs() and fgets() are string(line) input/output function in C.

The fputs() function writes the string pointed to by string variable to the specified stream. It returns EOF if an error occurs.Since fputs() does not automatically add a new line character to the end if the string; we must do this explicitly to read the string back from the file.

The fgets() function reads a string from the specified stream until either a new line character is read or length-1 character have been read. The function fgets() takes three arguments: the first is the address where the string is stored, the second is the maximum length of the string, and the third is the pointer to the structure FILE. When all the lines from the file have been read, if we attempt to read one more time it will return NULL.

Here is a sample program that writes strings to a file using the function fputs() and reads string from the file using fgets() function.

Example 3
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<string.h>
main()
{
char string[25];
FILE *fp;
fp=fopen("file3.txt","a+");
if(fp==NULL)
{
puts("can not open file");
exit(1);
}
do
{
printf("Enter a string to store in data file:");
gets(string);
strcat(string,"\n"); //add new line, since fgets() does not automatically add new line character to the end of the string
fputs(string,fp);
}while(*string!='\n');
rewind(fp);
while(!feof(fp))
{
fgets(string,2,fp);
puts(string);
}
fclose(fp);
getch();
}
 
In this example, while writing to a data file do while loop is used, which allows you to enter any number of strings. To stop entering you have to press enter key at the beginning (i.e. new line character should appear at the beginning). Similarly strings can be read from the data file until the end-of-file is reached.


Using rewind() function
The rewind() function resets the file position indicator to the beginning of the file specified as its arguments. That is, it "rewinds" the file. Its protype is
            void rewind(FILE *fp);
where fp is a valid file pointer.
In Example 1 and Example 3 the rewind() function is used after input is complete to move file position indicator at the beginning so that data can be read from the beginning.

10.4 Formatted Disk I/O Functions in file
For formatted reading and writing of characters, strings, integers, float, there exist two functions: fscanf() and fprintf(). Here is a sample program which illustrates the use of these functions.
Program to write information to a file and read from using formatted Input/Output.
Example 4
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
main()
{
char choice;
char name[40];
int age;
float height;
FILE *fp;
fp=fopen("myname.txt","w+");
do
{
printf("\nEnter name:");
scanf("%s",name);
fflush(stdin);
printf("\nEnter age:");
scanf("%d",&age);
fflush(stdin);
printf("\nEnter height:");
scanf("%f",&height);
fflush(stdin);
printf("\nDo you wish to continue:");
scanf("%c",&choice);
fprintf(fp,"%s\t%d\t%f",name,age,height);
}while(choice=='Y'||choice=='y');
rewind(fp);
while(!feof(fp))
{
fscanf(fp,"%s%d%f",name,&age,&height);
printf("\n%s\t%d\t%0.2f",name,age,height);
}
fclose(fp);
getch();
}
In this program the function fprintf() writes the values of three variables to the file. This function is similar to printf(), except that a FILE pointer is included as the first argument.The function fflush() is designed to remove or flush out any data remaining in the buffer. The argument to fflush() must be the buffer which we want to flush out. Here we use 'stdin', which means buffer related with standard input device, the keyboard. The fscanf() function is used to read the data from the disk. This function is similar to scanf(), except that, as with fprintf(), a pointer to FILE is included as the first argument.

10.5 Record Input/Output functions in file
In above cases we found that storing number in the format provided by formatted Input/Output functions take up a lot of disk space, because each digit is stored as a character. Similarly, formatted Input/Output has another problem: there is not direct way to read and write complex data types such as arrays and structures. Arrays can be handled but inefficiently by writing each array element one at a time.
A possible solution for this problem is record input/output, which is sometimes called "block input/output". Record input/output writes number to disk file in binary(or "untranslated") format, so that integers are stored in 4 bytes, floating point number in 4 bytes, and so on for the other numerical types. Record I/O also permits writing any amount of data at once. Array, structures, and other data constructions can be written with a single statement. The functions used for this purpose are fread() and fwrite().

fread() and fwrite()
To read and write data types that are longer than one byte, the C file system provides two functions: fread() and fwrite(). These functions allow the reading and writing of blocks of any  type of data (they are used for reading/writing records with binary file). The following program writes and reads data to and from binary file.
Program to write and read the data of structure to and from data file
Example 5
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
struct employee
{
char name[40];
int age;
float basicsal;
};
main()
{
struct employee e;
FILE *fp;
char choice;
fp=fopen("employee.txt","a+b");
if(fp==NULL)
{
printf("Can not open file!");
exit(0);
}
do
{
printf("Enter name,age, and basic salary:\n");
scanf("%s%d%f",e.name,&e.age,&e.basicsal);
fwrite(&e,sizeof(e),1,fp);
fflush(stdin);
printf("Add another record(Y/N)");
scanf("%c",&choice);
}while(choice=='Y'||choice=='y');

rewind(fp); //Moves file pointer to the beginning to read from the beginning

while(!feof(fp))
{
fread(&e,sizeof(e),1,fp);
printf("\n%s\t%d\t%f",e.name,e.age,e.basicsal);
}
fclose(fp);
getch();
}
The information obtained about the employee from the keyboard is placed in the structure variable e. Then, the following statement writes the structure to the file.
                        fwrite(&e,sizeof(e),1,fp);
Here, the first argument is the address of the structure to be written to the disk. The second argument is the size of the structure in bytes. Instead of counting the bytes occupied by the structure ourselves, we let the program do it for us by using sizeof() operator, which gives the size of the variable in bytes. The third argument is the number of such structures that we want to write at one time. In this case, we want to write only one structure at a time. The last argument is the pointer to the file we want to write to.
The fread() function causes the data read from the disk to be placed in the structure variable e. The format of fread() is same as fwrite(). The function fread() returns the number of records read. If we have reached the end of file, since fread() can not read anything, it returns 0.

Program on reading and wrting arrays with record I/O functions
Example 6
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
int table[10]={1,2,3,4,5,6,7,8,9,10};
main()
{
FILE *ftp;
ftp=fopen("table.txt","wb+");
if(ftp==NULL)
{
printf("Can not open file");
exit(0);
}
else
   fwrite(table,sizeof(table),1,ftp);
printf("Data has been written on file successfully....\n");
rewind(ftp);
while(!feof(ftp))
fread(table,sizeof(table),1,ftp);
for(int i=0;i<10;i++)
{
 printf("%d\t",table[i]);
}
fclose(ftp);
getch();
}

ftell() function
ftell() returns the current file pointer for stream. The offset is measured in bytes from the beginning of the file (if the file is binary).
Its prototype is
            long int ftell(FILE *stream);
The value returned by ftell can be used in a subsequent call to fseek.
ftell returns the current file pointer position on success. It returns -1L on error and sets the global variable errno to a positive value.
In the event of an error return the global variable errno is set to one of the following values:
EBADF            Bad file pointer
ESPIPE            Illegal seek on device

/* ftell example */
#include <stdio.h>
main()
{
   FILE *stream;
   stream = fopen("MYFILE.TXT", "w+");
   fprintf(stream, "This is a test");
   printf("The file pointer is at byte %ld\n", ftell(stream));
   fclose(stream);
   getch();
}

fseek() function
Repositions a file pointer on a stream.
fseek() sets the file pointer associated with stream to a new position that is offset bytes from the file location given by origin.
Syntax:
            int fseek(FILE *stream, long offset, int origin);
offset is the number of bytes from the origin that will become the new current position.
For text mode streams offset should be 0 or a value returned by ftell().
origin must be one of the values 0, 1, or 2 which represent three symbolic constants (defined in stdio.h) as follows:

Constant           Origin               File location
SEEK_SET      0                      File beginning
SEEK_CUR    1                      Current file pointer position
SEEK_END    2                      End-of-file
After fseek the next operation on an update file can be either input or output.
Return Value
fseek returns 0 if the pointer is successfully moved and nonzero on failure.

Random File Processing
Example 7
#include<stdio.h>
#include<conio.h>
struct employee
{
char name[10];
char address[15];
long int phone;
char qualification[10];
}emp[5],emp1;
main()
{
int endposition,current_position,total_no,n,i;
FILE *fptr;
fptr=fopen("random.txt","a+");
char choice;
for(i=0;i<5;i++)
{
   printf("Enter the name:");
   scanf("%s",emp[i].name);
   printf("Enter the address:");
   scanf("%s",emp[i].address);
   printf("Enter Phone No:");
   scanf("%ld",&emp[i].phone);
   printf("Enter Qualification:");
   scanf("%s",emp[i].qualification);
   fwrite(&emp[i],sizeof(struct employee),1,fptr);
   clrscr();
}
rewind(fptr);
fseek(fptr,0,SEEK_END);
endposition=ftell(fptr);
total_no=endposition/sizeof(struct employee);
do
{
   printf("There are %d structures,which u want to view?",total_no);
   scanf("%d",&n);
   current_position=(n-1)*sizeof(struct employee);
   fseek(fptr,current_position,SEEK_SET);
   fread(&emp1,sizeof(struct employee),1,fptr);
   printf("\n The name is %s\n",emp1.name);
   printf("The address is %s\n",emp1.address);
   printf("The phone no is %ld\n",emp1.phone);
   printf("The qualification is %s\n",emp1.qualification);
   fflush(stdin);
   printf("Do u want to see some other records(Y/N):");
   scanf("%c",&choice);
   clrscr();
}while(choice=='Y'||choice=='y');
fclose(fptr);
getch();
}

End of Chapter Ten
[ Note: If you have any problems regarding this then you can post the problem in comment box. we will try to solve this here. Or if you know any solution, you can also help :) ]