Binary files are very similar to arrays of records, except the records are in a disk file rather than in an array in memory. Because the records in a binary file are on disk, you can create very large collections of them (limited only by your available disk space). They are also permanent and always available. The only disadvantage is the slowness that comes from disk access time.
Binary files have two features that distinguish them from text files: You can jump instantly to any record in the file, which provides random access as in an array; and you can change the contents of a record anywhere in the file at any time. Binary files also usually have faster read and write times than text files, because a binary image of the record is stored directly from memory to disk (or vice versa). In a text file, everything has to be converted back and forth to text, and this takes time.
Pascal supports the file-of-records concept very cleanly. You declare a variable such as var f:file of rec; and then open the file. At that point, you can read a record, write a record, or seek to any record in the file. This file structure 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 record and moves the pointer down one record. Any write operation writes to the currently pointed-to record and moves the pointer down one record. Seek moves the pointer to the requested record.
In C, the concepts are exactly the same but less concise. 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.
The following program illustrates these concepts:
#include
/* random record description - could be anything */
struct rec
{
int x,y,z;
};
/* writes and then reads 10 arbitrary records from the file "junk". */
void main()
{
int i,j;
FILE *f;
struct rec r;
/* create the file of 10 records */
f=fopen("junk","w");
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");
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");
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");
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+");
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");
for (i=1;i<=10; i++)
{
fread(&r,sizeof(struct rec),1,f);
printf("%d\n",r.x);
}
fclose(f);
}
In this program, a meaningless record description rec has been used, but you can use any record 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: a memory address, the number of bytes to read per block, the number of blocks to read, and the file variable. Thus, the line fread(&r,sizeof(struct rec),1,f); says to read 12 bytes (the size of rec) from the file f (from the current location of the file pointer) into memory address &r. One block of 12 bytes is requested. It would be just as easy to read 100 blocks from disk into an array in memory by changing 1 to 100.
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: SEEK_SET, SEEK_CUR and SEEK_END. SEEK_SET moves the pointer x bytes down from the beginning of the file (from byte 0 in the file). SEEK_CUR moves the pointer x bytes down from the current pointer position. SEEK_END moves the pointer from the end of the file (so you must use negative offsets with this option).
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.
Binary files have two features that distinguish them from text files: You can jump instantly to any record in the file, which provides random access as in an array; and you can change the contents of a record anywhere in the file at any time. Binary files also usually have faster read and write times than text files, because a binary image of the record is stored directly from memory to disk (or vice versa). In a text file, everything has to be converted back and forth to text, and this takes time.
Pascal supports the file-of-records concept very cleanly. You declare a variable such as var f:file of rec; and then open the file. At that point, you can read a record, write a record, or seek to any record in the file. This file structure 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 record and moves the pointer down one record. Any write operation writes to the currently pointed-to record and moves the pointer down one record. Seek moves the pointer to the requested record.
In C, the concepts are exactly the same but less concise. 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.
The following program illustrates these concepts:
#include
/* random record description - could be anything */
struct rec
{
int x,y,z;
};
/* writes and then reads 10 arbitrary records from the file "junk". */
void main()
{
int i,j;
FILE *f;
struct rec r;
/* create the file of 10 records */
f=fopen("junk","w");
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");
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");
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");
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+");
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");
for (i=1;i<=10; i++)
{
fread(&r,sizeof(struct rec),1,f);
printf("%d\n",r.x);
}
fclose(f);
}
In this program, a meaningless record description rec has been used, but you can use any record 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: a memory address, the number of bytes to read per block, the number of blocks to read, and the file variable. Thus, the line fread(&r,sizeof(struct rec),1,f); says to read 12 bytes (the size of rec) from the file f (from the current location of the file pointer) into memory address &r. One block of 12 bytes is requested. It would be just as easy to read 100 blocks from disk into an array in memory by changing 1 to 100.
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: SEEK_SET, SEEK_CUR and SEEK_END. SEEK_SET moves the pointer x bytes down from the beginning of the file (from byte 0 in the file). SEEK_CUR moves the pointer x bytes down from the current pointer position. SEEK_END moves the pointer from the end of the file (so you must use negative offsets with this option).
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.
No comments:
Post a Comment