3.1.2 Random access

If a file is opened with "r+" or "w+" as the mode parameter in fopen, then the file can be read from and written to. This feature is useful when combined with the use of fseek and other related file position functions.

Essentially, the position of a file is an unsigned integer that indicates the byte location (relative to the beginning of the file) that the next read or write operation will use (but not when fopen uses "a+" as the mode). fseek goes to a particular location in a file, ftell returns the current file position. rewind goes back to position 0.

fgetpos and fsetpos are kind of like ftell and fseek, respectively. However, the f...pos subroutines can utilize complex structures to represent the file position, instead of just a long integer. This means that using ftell and fseek, access to a file cannot go beyond $ 2^31-1$ bytes (about 2GB). However, with f...pos, the limitation is all based on the type fpos_t, which can be a structure that has no practical range limitations.

Note that you can also access beyond the 32-bit integer range limit by using fseeko and ftello. These functions are similar to fseek and ftell, but the file position parameter is of the type off_t, which can become 64-bit integers with the macro _FILE_OFFSET_BITS defined as 64.

With file position functions, we can acquire and control the ``address'' of a structure in the file. This means we can implement ``pointers'' with structures that live in a file. The following is an example of a structure that lives in memory:

struct X
{
  char name[30];
  char gender;
  struct X *nextItem;
};

If the same structure is to live in a file, then we need to change the structure definition as follows:

struct X
{
  char name[30];
  char gender;
  off_t nextItem; // this is now a file position!
};

A structure still needs to be loaded into memory because we can do anything with it. With the above structure definition, we can print a list of structures using the following code (assuming pFile is already set up, and the file position is already at the beginning of a structure):

struct X aRecord;
do
{
  if (!fread(&aRecord, sizeof(aRecord), 1, pFile))
  {
    // error handling code
  }
  printf("%s [%c]\n", aRecord.name, aRecord.gender);
  if (aRecord.nextItem >= 0)
  {
    fseeko(pFile, aRecord.nextItem, SEEK_SET);
  }
} while (aRecord.nextItem >= 0);

There are important difference between memory structures and file structures. Memory structures live in the process heap, which is shared amongst threads. As long as threads do not step on each other, it is okay to share a heap amongst threads. However, it is not a good idea to permit threads to operate on the same file, even if they do not step on the same structure.

Copyright © 2006-10-16 by Tak Auyeung