Binary files have two features that distinguish them from text files:
C supports the file-of-structures concept very cleanly. Once you open the file you can read a structure, write a structure, or seek to any structure in the file. This file concept supports the concept of a file pointer. When the file is opened, the pointer points to record 0 (the first record in the file). Any read operation reads the currently pointed-to structure and moves the pointer down one structure. Any write operation writes to the currently pointed-to structure and moves the pointer down one structure. Seek moves the pointer to the requested record.
Keep in mind that C thinks of everything in the disk file as blocks of bytes read from disk into memory or read from memory onto disk. C uses a file pointer, but it can point to any byte location in the file. You therefore have to keep track of things.
The following program illustrates these concepts:
#include <stdio.h>
/* random record description - could be anything */
struct rec
{
int x,y,z;
};
/* writes and then reads 10 arbitrary records
from the file "junk". */
int main()
{
int i,j;
FILE *f;
struct rec r;
/* create the file of 10 records */
f=fopen("junk","w");
if (!f)
return 1;
for (i=1;i<=10; i++)
{
r.x=i;
fwrite(&r,sizeof(struct rec),1,f);
}
fclose(f);
/* read the 10 records */
f=fopen("junk","r");
if (!f)
return 1;
for (i=1;i<=10; i++)
{
fread(&r,sizeof(struct rec),1,f);
printf("%d\n",r.x);
}
fclose(f);
printf("\n");
/* use fseek to read the 10 records
in reverse order */
f=fopen("junk","r");
if (!f)
return 1;
for (i=9; i>=0; i--)
{
fseek(f,sizeof(struct rec)*i,SEEK_SET);
fread(&r,sizeof(struct rec),1,f);
printf("%d\n",r.x);
}
fclose(f);
printf("\n");
/* use fseek to read every other record */
f=fopen("junk","r");
if (!f)
return 1;
fseek(f,0,SEEK_SET);
for (i=0;i<5; i++)
{
fread(&r,sizeof(struct rec),1,f);
printf("%d\n",r.x);
fseek(f,sizeof(struct rec),SEEK_CUR);
}
fclose(f);
printf("\n");
/* use fseek to read 4th record,
change it, and write it back */
f=fopen("junk","r+");
if (!f)
return 1;
fseek(f,sizeof(struct rec)*3,SEEK_SET);
fread(&r,sizeof(struct rec),1,f);
r.x=100;
fseek(f,sizeof(struct rec)*3,SEEK_SET);
fwrite(&r,sizeof(struct rec),1,f);
fclose(f);
printf("\n");
/* read the 10 records to insure
4th record was changed */
f=fopen("junk","r");
if (!f)
return 1;
for (i=1;i<=10; i++)
{
fread(&r,sizeof(struct rec),1,f);
printf("%d\n",r.x);
}
fclose(f);
return 0;
}
In this program, a structure description rec has been used, but you can use any structure description you want. You can see that fopen and fclose work exactly as they did for text files.
The new functions here are fread, fwrite and fseek. The fread function takes four parameters:
The fwrite function works the same way, but moves the block of bytes from memory to the file. The fseek function moves the file pointer to a byte in the file. Generally, you move the pointer in sizeof(struct rec) increments to keep the pointer at record boundaries. You can use three options when seeking:
Several different options appear in the code above. In particular, note the section where the file is opened with r+ mode. This opens the file for reading and writing, which allows records to be changed. The code seeks to a record, reads it, and changes a field; it then seeks back because the read displaced the pointer, and writes the change back.
For more information on C and related topics, check out the links on the next page.
More Options: