Files
A magnetic disk, known as disk, is a circular piece of metal or plastic, whose surface is coated with a magnetically chargeable substance. Data/information is stored on a disk by magnetizing certain portions of it. This is accomplished by the read/write head of the disk drive. The most common form of disks is floppy disks and hard disks.
You can not store data directly on the disk. Data is stored on disk if it is embedded in a file. A file is just a collection of related data/information. A file resides on disk rather than on memory. The main advantage of using disk files is that disk files enable us to save our data permanently on disk and retrieve them later on when needed. In many programming situations, it is easier to access a file than to enter a succession of individual data items from the keyboard.
The common operations associated with file processing are:
(i) reading from a file (input)
(ii) writing to a file (output)
(iii) appending to a file (writing at the end)
(iv) updating a file (input/output)
Whenever we will deal with files in a C program, it is always done in the following sequence:
Open the file
Read/Write from/to the file
Close the file
Now some important functions that necessary while working with files.
The File Protocol : fopen() and fclose() Functions
A file is opened by using the function fopen(). When a file is opened for I/O using the stream functions, the opened file is associated with a structure of type FILE (defined in stdio.h) containing the basic information about the file. When a stream is opened, a pointer to the FILE structure is returned. Subsequent operations use this file pointer (also called as “stream pointer” or just “stream”) to refer to the file.
Each file has its own structure of type FILE associated with it. Once you include the file , declaration of file pointer is the next step. A file pointer is declared as:
FILE *fptr;
Here fptr is a pointer variable pointing to the structure FILE. You can also declare more than one file pointers at the same time as:
FILE *fptr1, *fptr2, *fptr3;
Here fptr1, fptr2 and fptr3 are file pointers.
fopen() Function
The fopen() function is used to open a file for reading and writing. You can open any file by using fopen() function before accessing it. The fopen() function returns a FILE pointer, which is used to refer to the stream. The fopen() function takes the following form:
fopen (filename, accessmode);
The filename is the name of the file to be opened. It may include the path. For example, if you want to open a file userfile.dat having full pathname “c:\temp\userfile.dat” then the filename used in fopen() should be used using double backslash as:
fopen (“c:\\temp\\userfile.dat”, accessmode);
The accessmode specifies the type of access requested for the file. The accessmode is one of the following strings:
- “r” opens a file for reading only (input). The only necessary condition is that the file must exist already.
- “w” opens a file for writing only (output). A file will be created if it does not exist already. If a file already exists then its previos contents are destroyed.
- “a” opens a file for appending data. A file will be created if it does not exist already. If a file already exists then the previous data will remain as it is and new data will be added at the end of the existing data.
- Adding a plus sign (+) to any of these three above modes creates one of the following three more new modes, which are called as updated modes.
- “r+” opens a file for update (reading and writing). The only necessary condition is that the file must exist already.
- “w+” opens a file for update (reading and writing). A file will be created if it does not exist already. If a file already exists then its previos contents are destroyed.
- “a+” opens a file for update (reading and appending). A file will be created if it does not exist already. If a file already exists then the previous data will remain as it is and new data will be added at the end of the existing data.
For example, in the following code segment:
FILE *fptr;
fptr = fopen("Input.txt", "r");
the fopen() returns a pointer to the opened stream and you can use the file pointer fptr to refer to the stream for reading only. The fopen() function returns a pointer to the opened stream if it succeeded. If fopen() fails it returns NULL. When we open a file using fopen() then the request for opening s file may not be granted due to some following reasons:
(i) Trying to open a file for reading which may not be present on the disk at all.
(ii) Trying to open a file and there is not enough space or the disk may be write-protected.
(iii) Trying to open a file that has been corrupted
Thus if fopen() fails due to any reason then we must handle this situation by inserting the following code segment just after calling of fopen() function:
FILE *fptr;
fptr = fopen("Input.txt", "r");
if (fptr == NULL)
{
printf("\nUnable to open a file.");
exit(0);
}
Earlier we have seen how to open a file in “r” (read) mode. Similarly we can open a file in “w” (write) or “a” (append) mode. The following line opens a file named “Report.txt” in the current directory for appending data:
FILE *fptr;
fptr = fopen("Report.txt", "a+");
fclose() Function
When you are through processing the file data, you have to close the file. The function fclose() is used to close the file. The fclose() function takes the following form:
fclose (fptr);
Here fptr is a file pointer. You can not use the file name as an argument to fclose() function. Till now we have studied how to open a file and close a file. Now we will study various file I/O functions that are used to transfer data to and from files.
File Input and Output
In C data are transferred to and from files in following ways:
Character I/O (one character input/output)
String I/O (one string input/output)
Record I/O (one record input/output)
Character I/O In Files
Character I/O involves of writing a character to a file and reading a character from a file. To write a character to a file, we use the function putc() and to read a character from a file we use getc().
The putc() and getc() Functions
The putc() function writes a character to the output stream (file pointer) at the current position, advances the pointer position so it can now write to the next position. The putc() function takes the following form:
putc(ch, fptr)
Here ch is the character to be written to the file and fptr is a file pointer of type FILE. The putc() function returns the character written. If it fails to write a character to the output stream; it returns a value EOF indicating an error.
The getc() is the counter part of putc(). The getc() function is used to read a character from the input stream (file pointer) from the current position at a time and increases the associated file pointer to point to next character. The getc() function takes the following form:
ch = getc(fptr)
Here fptr is a file pointer of type FILE. The getc() reads the character from the current file pointer position, advances the pointer position so that it now points to the next character and returns the character that is read. This character is collected in a character variable ch.
Program-F1.c illustrates the use of putc() and getc() functions.
/* Program – F1.c */
#include
#include
main()
{
char ch;
int i;
FILE *fptr;
char str[] = "Honesty is the best policy.";
fptr = fopen("File1.txt", "w");
if (fptr == NULL)
{
printf("\nUnable to open a file.");
exit(0);
}
i=0;
while (str[i] != '\0')
{
ch = str[i];
putc(ch,fptr);
i++;
}
fclose(fptr);
fptr = fopen("File1.txt", "r");
if (fptr == NULL)
{
printf("\nUnable to open a file.");
exit(0);
}
printf("\nOutput from file….");
while ( (ch=getc(fptr)) != EOF)
printf("%c", ch);
fclose(fptr);
}
Here is the output of this program….
Honesty is the best policy.
The fgetc() and fputc() Functions
Like getc() and putc(), fgetc() and fputc() reads and writes a character from or to the file. The only difference is that getc() and putc() are implemented as macros whereas fgetc() and fputc() are implemented as ordinary functions.
The feof() function
In this program you have used fgetc() and fputc() functions. You can also write the while loop in a more compact way as:
while ( (ch==fgetc(fs)) != EOF)
fputc(ch, fd);
Here first fgetc() gets a character from the file, assigns it to ch, and then ch is compared against EOF. And it is also mandatory to enclose the expression ch==fgetc(fs) within a pair of parentheses so that first the character is assigned to the variable ch and then it is compared with EOF.
Fortunately there is one more way of writing the while loop, as follows:
while (!feof(fs))
{
ch = fgetc(fs);
fputc(ch, fd);
}
Here feof() is a macro which returns a 0 if end of file is not reached; otherwise returns a non-zero value. We have used the ! (NOT) operator to negate 0 to 1 (true-value). Thus when the end of file reaches, the feof() returns a non-zero value and the ! operator makes it 0 and as the condition evaluates to false the while loop gets terminated.
String I/O In Files
Reading and writing of strings from and to files is as easy as reading and writing of individual characters. String I/O functions are used to transfer your data one string at a time from and to files. C provides two main functions that deals with string I/O in files: fputs() and fgets().
The fputs() and fgets() Function
The fputs() function writes a string to the output stream at current file pointer position. The NULL (‘\0’) character is not written to the file. The fputs() function takes the following form:
fputs (str, fptr);
Here str is the pointer to string to be written to the file and fptr is a file pointer of type FILE structure which specifies the name of the file to which the output has to be written. The fputs() function returns a zero value if it succeeds; otherwise returns a non-zero value.
The fgets() function reads a string from the input stream and stores in a string at a time. The fgets() function takes the following form:
fgets (str, n, fptr);
Here str is the base address where the string is to be stored, n is the number of characters to be stored and fptr is a file pointer of type FILE structure which specifies the name of the file to which the input has to be read. The fputs() function returns the starting address of str; otherwise returns NULL. The fgets() function reads characters from the current file pointer position upto and including the first new line character ‘\n’, upto the end of the stream, or until the number of characters read is equal to (n-1), whichever comes first. Now look at the second argument of fgets() function more carefully. This second argument is used to prevent fgets() from reading a too long string and overflowing the array.
Let us see a program that illustrates the use of fputs() and fgets() function.
/* Program – F2.c */
#include
#include
main()
{
FILE *fptr;
char str[40];
fptr = fopen("Players.txt", "w");
if (fptr == NULL)
{
printf("\nUnable to open a file.");
exit(0);
}
printf("\nEnter name (type - stop to exit) : ");
gets(str);
while ((strcmp(str,"stop") != 0))
{
fputs(str, fptr);
fputs("\n", fptr);
printf("Enter name (type - stop to exit) : ");
gets(str);
}
fclose(fptr);
fptr = fopen("Players.txt", "r");
if (fptr == NULL)
{
printf("\nUnable to open a file.");
exit(0);
}
printf("\nFile name : Players.txt \n");
while ((fgets(str,40,fptr) != NULL))
printf("%s", str);
fclose(fptr);
}
When you run this program you get the following output….
Here is the sample sun of this program….
Enter name (type - stop to exit) : Sachin Tendulkar
Enter name (type - stop to exit) : Virender Sehwag
Enter name (type - stop to exit) : Sourav Ganguly
Enter name (type - stop to exit) : Rahul Dravid
Enter name (type - stop to exit) : Youvraj Singh
Enter name (type - stop to exit) : Mohammad Kaif
Enter name (type - stop to exit) : stop
File name : Players.txt
Sachin Tendulkar
Virender Sehwag
Sourav Ganguly
Rahul Dravid
Youvraj Singh
Mohammad Kaif
Since fptr does not automatically insert a new line character (‘\n’) to the end of the string, we must do this explicitly to make it easier to get the string back from the file.
Record I/O in File
Till now we have studied only unformatted disk I/O functions. Like console I/O functions, C also provides the facility of formatted I/O for disk. C provides two types of disk formatted functions: fscanf() and fprintf().
The fprintf() and fscanf() Functions
The fprintf() function writes formatted data to the output stream. This data can be integers, floats, characters or strings. The fprintf() function takes the following form:
fprintf (fptr, “format string”[, arg1, arg2, …., argn]);
Here fptr is a file pointer of type FILE structure. Each argument, if any, is convertd and output according to the corresponding format specifier in the format string. The fprint() returns the number of characters printed. This function is similar to printf(), except that a FILE pointer is included as the first argument. Like printf(), you can format the data in a variety of ways by using fprintf(). As far as the format conversion is concerned, the fprintf() works same as printf().
The fscanf() function reads formatted the correct position of an input stream into the location given by the arguments, if any. This data can be integers, floats, characters or strings. The fscanf() function takes the following form:
fscanf (fptr, “format string”, arg1, arg2, …., argn);
Here fptr is a file pointer of type FILE structure. However the concept of “format string” and arg1, arg2, …., argn are same as we have studied in scanf() function. Each argument must be a pointer to a variable with a type that corrersponds to a type specifier in the format string. The fscanf() returns the number of fields that were successfully converted and assigned. On failure it reutrns EOF.
Program-F3.c illustrates the use of fprintf() function.
/* Program – F3.c */
#include
#include
#include
main()
{
FILE *fptr;
char name[25];
int age;
float salary;
char ch;
fptr = fopen("Emp.txt", "w");
if (fptr == NULL)
{
printf("\nUnable to open a file.");
exit(0);
}
ch = 'y';
while (ch=='y')
{
printf("\nEnter name : ");
gets(name);
printf("Enter age : ");
scanf("%d", &age);
printf("Enter salary : ");
scanf("%f", &salary);
fprintf(fptr, "%s %d %f", name, age, salary);
fflush(stdin);
printf("\nAny more input (y/n) : ");
ch = tolower(getche());
}
fclose(fptr);
}
Here is the sample run of this program….
Enter name : Sagar
Enter age : 24
Enter salary : 12000.50
Any more input (y/n) : y
Enter name : Amitab
Enter age : 40
Enter salary : 24600.60
Any more input (y/n) : y
Enter name : Rahul
Enter age : 21
Enter salary : 15800.50
Any more input (y/n) : y
Enter name : DayaNand
Enter age : 35
Enter salary : 21500.50
Any more input (y/n) : n
In this program i have used fflush(). The reason behind the use of fflush() is that after reading data for an employee an Enter key is being hit. The scanf() function assigns name, age and salary to appropriate variables and keeps the Enter key unread in the keyboard buffer (stdin). Therefore when getche() function is waiting for a character it reads the Enter key from the keyboard thinking that user has entered the key. To overcome this problem we use fflush(). The fflush() function is used to flush out any pending data in the buffer.
Program-F4.c shows the use of fprintf() and fscanf() functions while writing of records to file.
/* Program – F4.c */
#include
#include
main()
{
FILE *fptr;
int i;
struct Employee
{
char name[25];
int age;
float salary;
};
struct Employee e;
char ch;
fptr = fopen("Emp1.txt", "w");
if (fptr == NULL)
{
printf("\nUnable to open a file.");
exit(0);
}
ch = 'y';
i=1;
while (ch=='y')
{
printf("\n\nEnter Record #%d : \n",i);
printf("\nEnter name : ");
gets(e.name);
printf("Enter age : ");
scanf("%d", &e.age);
printf("Enter salary : ");
scanf("%f", &e.salary);
fprintf(fptr, "%s %d %f", e.name, e.age, e.salary);
fflush(stdin);
printf("\nAny more input (y/n) : ");
ch = tolower(getche());
i++;
}
fclose(fptr);
fptr = fopen("Emp1.txt", "r");
if (fptr == NULL)
{
printf("\nUnable to open a file.");
exit(0);
}
i=1;
while (fscanf(fptr, "%s %d %f", e.name, &e.age, &e.salary) != EOF)
{
printf("\nRecord #%d\n", i);
printf("\n Name : %s", e.name);
printf("\n Age : %d", e.age);
printf("\n Salary : %f\n", e.salary);
i++;
}
fclose(fptr);
}
Here is a sample run of this program….
Enter Record #1 :
Enter name : Ajay
Enter age : 20
Enter salary : 15000.75
Any more input (y/n) : y
Enter Record #2 :
Enter name : Rohit
Enter age : 20
Enter salary : 13450.50
Enter Record #3 :
Enter name : Shrey
Enter age : 18
Enter salary : 14000.50
Any more input (y/n) : n
Record #1
Name : Ajay
Age : 20
Salary : 15000.750000
Record #2
Name : Rohit
Age : 20
Salary : 13450.500000
Record #3
Name : Shrey
Age : 18
Salary : 14000.500000
The fwrite() and fread() Functions
The fwrite() function is used to write a block of data (say structure, array) to the file. The fwrite() function takes the following form:
fwrite (ptr, size, n, fptr);
Here ‘ptr’ is the pointer to the data to be written, ‘size’ is the length of each data item, ‘n’ is the maximum number of data items to be written of ‘size’ and finally ‘fptr’ is a file pointer type FILE structure. The file pointer associated with fptr is incremented by the number of bytes actually written.
For example:
struct Employee
{
char name[25];
int age;
float salary;
};
struct Employee e;
then fwrite() function is used as:
fwrite(&e, sizeof(e), 1, fptr);
Here fwrite() writes 31 bytes of information at the current file pointer position ‘fptr’.
The fread() function is the counter part of fwrite() function. The fread() function is used to read a block of data from the file. The fread() function takes the following form:
fread (ptr, size, n, fptr);
Here ptr is the address of data item (an array or a structure) where the block of data will be stored after reading, size is the size of the data item in bytes to be read, n is the number of data items and fptr is the file pointer of type FILE structure. The fread() function returns the number of full data items actually read, which may be less than ‘n’ (possibly 0) if function causes any error.
For example:
struct Employee
{
char name[25];
int age;
float salary;
};
struct Employee e;
then fread() function is used as:
fread(&e, sizeof(e), 1, fptr);
Here fread() reads 31 bytes of information from the current file pointer position ‘fptr’ and stores the information in the structure variable ‘e’.
Program-F5.c illustrates the use of fwrite() and fread() functions.
/* Program –F5.c */
#include
#include
main()
{
FILE *fptr;
int i;
struct Employee
{
char name[25];
int age;
float salary;
};
struct Employee e;
char ch;
fptr = fopen("Emp2.bin", "wb");
if (fptr == NULL)
{
printf("\nUnable to open a file.");
exit(0);
}
ch = 'y';
i=1;
while (ch=='y')
{
printf("\n\nEnter Record #%d : \n",i);
printf("\nEnter name : ");
gets(e.name);
printf("Enter age : ");
scanf("%d", &e.age);
printf("Enter salary : ");
scanf("%f", &e.salary);
fwrite(&e, sizeof(e), 1, fptr);
fflush(stdin);
printf("\nAny more input (y/n) : ");
ch = tolower(getche());
i++;
}
fclose(fptr);
}
Here is the sample run of this program….
Enter Record #1 :
Enter name : Ashok
Enter age : 30
Enter salary : 24000.50
Any more input (y/n) : y
Enter Record #2 :
Enter name : Bhism
Enter age : 26
Enter salary : 18060.70
Any more input (y/n) : y
Enter Record #3 :
Enter name : Sourav
Enter age : 32
Enter salary : 23600.50
Any more input (y/n) : n
File Positioning : Random Access Files
All disk I/O functions discussed so far use sequential access. Read/Write operations are performed from the beginning to the end in one direction only. However a file can also be accessed randomly using random access function, as shown in table-1
Random Access Functions |
|
Function |
Meaning |
fseek() |
Sets the file pointer |
fgetpos() |
Gets the current position of the file pointer |
ftell() |
Gets the current position of the file pointer |
fsetpos() |
Sets the file pointer |
rewind() |
Sets the file pointer to the beginning of the file |
Table 1
In a random access data can be read or written from or to a specific portion of a file using random access functions. Let us study these random access functions.
fseek() Function
The fseek() function moves the file position associated with file pointer to a new location. The fseek() function takes the following form:
fseek(fptr, offset, origin);
Here fptr is a file pointer of type FILE structure, offset is the position, expressed in bytes, relative to a point specified by origin. The offset is long int data type. The origin may be 0, 1 or 2. If the origin is specified as 0 then it means that offset is relative to the beginning of the file. If the origin is 1 then it means that offset is relative to the current position. Finally if the origin is 2 then it means that offset is relative to the end of the file and hence it must have negative offset value.
Fortunately C defines three macros SEEK_SET, SEEK_CUR and SEEK_END in a header file which represent 0, 1 and 2 origin respectively. The fseek() function returns 0 if it succeeds; otherwise it returns a non-zero value. The fseek() function can be used to reposition the file pointer nay where in a file.
fgetpos() Function
The fgetpos() function gets the current value of file pointer. The fgetpos() function takes the following form:
fgetpos(fptr, pos);
Here fptr is a file pointer of type FILE structure and pos be the new position of the file pointer. On success this function returns 0; otherwise returns a non-zero value.
ftell() Function
The ftell() function is used to obtain the current file pointer position. The ftell() function takes the following form:
ftell(fptr);
Here fptr is a file pointer of type FILE structure. The ftell() function returns the long int value; otherwise it returns –1L. The value returned by ftell() can be used in a subsequent call to fseek().
fsetpos() Function
The fsetpos() function sets the file pointer to the value specified. The fsetpos() function takes the following form:
fsetpos(fptr, pos);
Here fptr is a file pointer of type FILE structure and pos be the new position of the file pointer. The value of pos is obtained by calling fgetpos(). On success this function returns 0; otherwise returns a non-zero value.
rewind() Function
The rewind() function is used to reset the current file pointer position to the beginning of the file. The rewind() function takes the following form:
rewind(fptr);
Here fptr is a file pointer of type FILE structure, which is to be placed to the beginning of the file irrespective of where it is present right now.