C Tutorial (29) : Disk files – Random access

This tutorial shows you how to skip around in a file, reading and writing data as you go. The preceding tutorial introduced methods you can use to write, read, or append data to a file. The problem is, when you open a sequential file for reading, you can only read it.

Sometimes you might want to read a customer structure from disk and change the customer’s balance. You certainly wouldn’t want to have to create a new file just so you could write that one change. Instead, you would want to read the customer information into a variable, change it, and then write it back to disk exactly where it first resided. As Random files let you skip around in the file, reading and writing at any point you access.

The physical layout of a file doesn’t define the type of file (whether random or sequential). You can create a file sequentially and then read and change it randomly. To C, a file is just a stream of bytes, and the way you access it isn’t linked to any format of the file.

Opening Random Files

To read or write a file randomly, you must open the file randomly. Table lists the modes that access random files. As you can see, the cornerstone of random-access files is the use of the plus sign combined with the access modes you learned about in the previous chapter.

c_file_random_access_mode

The Random-Access fopen() Modes

Note : You close open random files with fclose(), just as you do with sequential files.

All three modes let you read and write to the file. The access mode you choose depends on what you want to do first to the file. If the file exists and you want to access the file randomly, use the r+ mode. If you want to create the file, use w+. (If the file already exists, C overwrites the existing version.) If you want to add to the end of a file but optionally “back up” and read and write existing data, use a+.

Here is a sample fopen() statement that opens a new file for writing and reading:

fptr = fopen("/tmp/letters.txt", "w+");

Tip : You can store the filename in a character array and use the character array name in place of an actual string literal for the filename.

Moving Around in a File

Use the fseek() function to move around in a file. After you open a file, C initializes the file pointer to point to the next place in the file you can read or write. fseek() moves the file pointer so that you can read and write at places that would normally not be pointed at using sequential access. Here is the format of fseek():

fseek(filePtr, longVal, origin);

The filePtr is the file pointer used in the fopen() function that used a random-access mode. The longVal is the number of bytes to skip forward or backward in the file. The origin is always one of the values shown in Table. origin tells fseek() where to start seeking.

c_fseek_vals

origin Values That Can Appear in fseek()

The origin value tells C the position from where you want to access the random file next. After you position the file pointer with fseek(), you can use file input and output functions to write and read to and from the file. If you position the file pointer at the end of the file (using SEEK_END) and then write data, new data goes to the end of the file. If you position the file pointer over existing data (using SEEK_SET and SEEK_CUR) and then write new data, the new data replaces the existing data.

Warning : Use fseek() for random-access files only. Sequential files can be accessed only in the order of the data.

Table’s values are in uppercase, which implies that they’re defined somewhere. They’re defined in stdio.h using #define directives.

The following program opens a file for random-access mode, writes the letters A through Z to the file, and then rereads those letters backward. The file doesn’t have to be reopened before the reading begins because of the random-access mode “w+”.

/* The program opens a file named letters.txt and 
   prints A through Z into the file. It then loops backward 
   through the file printing each of the letters from Z to A. */

#include <stdio.h>
#include <string.h> 

FILE * fptr;

main()
{

char letter; 
int i;

fptr = fopen("/tmp/letters.txt", "w+");
if (fptr == 0)
{
printf("There was an error while opening the file.\n"); 
exit(1);
}

for (letter = 'A'; letter <= 'Z'; letter++)
 {
 fputc(letter, fptr);
 }
 puts("Just wrote the letters A through Z"); 

// Now read the file backwards 
fseek(fptr, -1, SEEK_END); // Minus 1 byte from the end  
printf("Here is the file backwards:\n"); 
for (i = 26; i > 0; i--)
{
letter = fgetc(fptr);
// Reads a letter, then backs up 2 
fseek(fptr, -2, SEEK_CUR);
printf("The next letter is %c.\n", letter);
}

fclose(fptr); // Again, always close your files

return(0);
}

Tip : As you can see, fputc() is a great function for outputting individual characters to a file. fgetc() reads individual characters from a file.

Random access offers you the advantage of writing data to a file and then rereading the same data without closing and opening the file. Also, fseek() lets you position the file pointer any number of bytes from the beginning, middle, or end of the file.

Assuming that the file of letters still resides on the disk from the last program, this next program asks the user which position he or she wants to change. The program then positions the file pointer with fseek() and writes an * at that point before using fseek() to return to the beginning of the file and printing it again.

/* The program opens the file created in the previous program
   and changes one of the letters to an *. It then prints the
   new list with the altered list of letters.*/

#include <stdio.h>
#include <string.h>

FILE * fptr;

main()
{
char letter; 
int i;

fptr = fopen("/tmp/letters.txt", "r+");
if (fptr == 0)
{
printf("There was an error while opening the file.\n"); 
exit(1);
}

printf("Which # letter would you like to change (1-26)? "); 
scanf(" %d", &i);

// Seeks that position from the beginning of the file 

fseek(fptr, (i-1), SEEK_SET); // Subtract 1 from the position 
                              // because array starts at 0
// Write an * over the letter in that position
fputc('*', fptr);

// Now jump back to the beginning of the array and print it out
fseek(fptr, 0, SEEK_SET); 
printf("Here is the file now:\n"); 
for (i = 0; i < 26; i++)
{
letter = fgetc(fptr);
printf("The next letter is %c.\n", letter);
}

fclose(fptr); // Again, always close your files 
return(0);
}

Note : If you ran this program a second time and changed a different letter (say, the 15th position of the alphabet, the O), your file would print with asterisks instead of H and O because the change to the H is now permanent in the letters.txt file.

Disk Files (Sequential Access) < Prev          Next > Function and local-global variables

Advertisements

2 comments

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s