¤ Home » Programming » C Tutorial » File Handling in C - Part 5 of 7

File Handling in C - Part 5 of 7

Structure based I/O functions - fread, fwrite

The functions fread and fwrite can read and write structures from and into a file respectively. While writing, the function fwrite compresses the numerical data that is why files thus created differ from an ordinary text file. Such files are referred as binary files. A file created by fwrite can successfully be read using fread function. The prototypes of these function declarations are described below:

  fread(<buffer-address>, <one-data-block-size>, <no-data-blocks>, <file-pointer>);
  fwrite(<buffer-address>, <one-data-block-size>, <no-data-blocks>, <file-pointer>);

In the above functions, the parameter buffer-address holds the address of the data block (in the main memory) to be read from or written to. The second parameter one-data-block-size, is the size of data block. The third parameter is the number of such data blocks (all data blocks should be structures of the same type) to be read or written, and the fourth parameter is the pointer to the file that is opened for reading (mode rb) or writing (mode wb or ab).

In case of success, fread returns the number of bytes actually read from the file. Like wise, fwrite returns the number of bytes actually written to the file. In case of failure, a lesser number of byes (then requested to read/write) is returned.

Not only structures, any sort of data object can be transferred from the buffer to the file or vice versa during input or output operations. For example, we can simply write an integer variable marks onto a file (fp is the associated file pointer) by the following statement:

  fwrite(&marks, sizeof(int), 1, fp);

Below is a simple example of writing into a binary file.

  const char *str = "I love the C Language";   
  FILE *fp = fopen("test.txt", "wb");   
  if(fp)
  {
    fwrite(str, sizeof(char), strlen(str), fp);
    fclose(fp);
  }

We will now show two methods to perform input/output operations with structures. The first one involves a simple structure variable, whereas the second one uses pointers to structures.

Method 1:

Consider the structure student,

  struct student{
    int   enrolment_no;
    char  name[21];
    char  course_name[11];
    float module_marks[4];
    char  grade;
  };
  student first;

  /* Read one student record */
  fread(&first, sizeof(student), 1, fp);

Method 2:
  student *ptr;
  ptr = (student *)malloc(sizeof(student));
  fread(ptr, sizeof(student), 1, fp);

As we have mentioned, fread returns the number of data blocks read successfully at the end of the input operation. The return value helps in evaluating the state of affairs as shown below.

  if(fread(ptr, sizeof(student), 1, fp) == 1)
  {
    /* the record is successfully read */
  }
  else
  {
    /* unsuccessful read attempt */
  }

Exercise:

Consider the skeletal C program provided below. Include suitable read and write statements to do the following:

  1. Read the structure data from the file old.fil.
  2. Display each of structure members value on the screen and change the value.
  3. Write the new values to the data file new.fil.

Hint: You may need to first create a binary file old.fil, pre-populated with a few blocks of data, by writing another program.

  #include<stdio.h>
  main(int argc, char *argv[])
  {
    struct data{
      int   i;
      float f;
      char  c;
    } dt;

	main()
	{
      FILE *fp1, *fp2;
		
      fp1 = fopen("old.fil", "rb");
      fp2 = fopen("new.fil", "wb");
      . . .
      . . .
      fclose(fp1);
      fclose(fp2);
    }


Checking of End of File using feof()

As already mentioned, fread function returns the number of data blocks read at the completion of a successful read operation. Function fread(), by itself, cannot communicate the occurrence of end of file. In a practical programming situation, when the end of file is encountered, fread may not respond properly (i.e. it may return no specific value). Hence, we use function feof() (a standard C library function) to detect occurence of end of file. The function feof() helps in trapping the occurrence of end of file and thus enhances program efficiency.


Repositioning file pointer - fseek(), ftell() and rewind() functions

While working with binary files, these are 3 much needed functions.

fseek()

The standard library function fseek enables direct access to data items in a file stream. This function sets the logical pointer in an opened file to a new position, from where the subsequent read or write operations can begin. Here is the prototype of fseek function:

 int fseek(FILE *file_pointer, long offset, int origin);

As you can see, the fseek function accepts three arguments. The first argument is the FILE stream pointer returned by fopen(). The second argument offset tells the amount of bytes to progress (seek) in order to reposition the logical pointer. The third argument origin tells from where the seek of offset number of bytes is to be done.

The origin may be either of the following:

The function fseek returns 0 on success and -1 on failure/error.


ftell()

The function ftell gives the current position of the logical pointer in the file. It tells the byte location of the current pointer position.


rewind()

If you intend to initiate subsequent operations from the beginning of the file (whatever may be the current logical pointer position), the function rewind helps in achieving it. It moves the control to beginning of the file. The function rewind() expects the file pointer as the only argument. Here is it's prototype:

  rewind(file_pointer);

The effect created by rewind() can also be simulated using the following call to fseek() function:

  fseek(file_pointer, 0L, 0);

Here is a typical example to illustrate the usage of the various functions we have learned about in this article.

/*
 Program to demonstrate usage of the following functions:
	- fread, fwrite, fseek, rewind, feof
 --------------------------------------------------------
*/

#include <stdio.h> 

typedef struct{
  char name[21];
  char tel[10];
} tele;
tele *t;

main()
{
  FILE *fp;
  char rp =' ', nm[21];

  fp = fopen("tele.dat", "ab");
  while(rp != 'n' && rp != 'N')
  {
    t = (tele *)malloc(sizeof(tele));
    printf("\nEnter Subscriber Name : ");
    gets(t->name); fflush(stdin);

    printf("\nEnter Telephone Number of %s : ", t->name);
    gets(t->tel); fflush(stdin);

    fwrite(t, sizeof(tele), 1, fp);

    printf("\nContinue to add more records (Y/N) ? ");
    rp = getchar(); fflush(stdin);
  }
  fclose(fp);

  printf("\n\nPrinting Contents of file:\n");
  printf("------------------------------\n");
  fp = fopen("tele.dat", "rb");
  do{
      fread(t, sizeof(tele), 1, fp);
      if(feof(fp)) break;
      printf("\n%s, %s\n", t->name, t->tel);
  }while(1);
  fclose(fp);

  printf("\n\nNow, Modify a record:\n");
  printf("-------------------------\n");
  fp = fopen("tele.dat", "rb+");
  rp = ' ';
  while(rp != 'n' && rp != 'N')
  {
    printf("\nEnter Name for whom the data is to be modified : ");
    gets(nm); fflush(stdin);
  
    while(1)
    {
      fread(t, sizeof(tele), 1, fp);
      if(!feof(fp))
      {
        if(strcmp(nm,t->name) == 0)
        {
          printf("Enter new number for %s : ", t->name);
          gets(t->tel); fflush(stdin);

          fseek(fp, -sizeof(tele),1);
          fwrite(t, sizeof(tele), 1, fp);
          break;
        }
      }
      else
      {
        printf("\nNo such Subscriber. EOF encountered \n");
        free(t);
        break;
      }
    }

    printf("Continue to modify another record (Y/N) ? ");
    rp = getchar(); fflush(stdin);
  }

  printf("\n\nPrinting Contents of file to view modifications:\n");
  printf("---------------------------------------------------\n");
  rewind(fp);
  do{
      fread(t, sizeof(tele), 1, fp);
	  if(feof(fp)) break;
      printf("\n%s, %s\n", t->name, t->tel);
  }while(1);
  fclose(fp);  
}


Exercises:

1. Match the following:

i.FILEa.checks for eof
ii.fseek(file_pointer, 0L, 0);b.is a symbolic constant defined in stdio.h
iii.feof()c.opens the file
iv.ftelld.position the file pointer to the top of the file
v.fopene.typedef structure defined in stdio.h
vi.EOFf.returns the offset byte position

2. Identify the current position of the logical file pointer and the number of offset bytes from the beginning of the file to the current position of the logical pointer after execution of each of the following statements:

  1. fp = fopen("text.demo", "r");
  2. fgets(word, 21, fp);
  3. fseek(fp, -51, 1);
  4. fputs(new_word, fp); /* new _word is 5 characters long including '\0' */
  5. fseek(fp, 0L, 2);
  6. fseek(fp, 15L, 0);



Share:




comments powered by Disqus


Buy Domain & Hosting from the most reliable and trusted company - WebServicesWorldWide.com.

Looking to build a website?
Launch a 20 page website in 1 day at only Rs.200/month or US$ 3.19/month. Hosting & Email included.





About the Author

Rajeev Kumar
CEO, Computer Solutions
Jamshedpur, India

Rajeev Kumar is the primary author of How2Lab. He is a B.Tech. from IIT Kanpur with several years of experience in IT education and Software development. He has taught a wide spectrum of people including fresh young talents, students of XLRI, industry professionals, and govt. officials.

Rajeev has founded Computer Solutions & WebServicesWorldwide.com, and has hands-on experience of building variety of web applications and portals, that include - SAAS based ERP & e-commerce systems, independent B2B, B2C, Matrimonial & Job portals, and many more.



Copyright © How2Lab.com. All rights reserved.

Refer a friend | Sitemap | Disclaimer | Privacy Policy