A Simple C Class

Chapter 11 - Complete I/O in C

Visual C++ 6: The Complete Reference
Chris H. Pappas and William H. Murray, III
  Copyright 1998 The McGraw-Hill Companies

Using fseek( ), ftell( ), and rewind( )
You can use the functions fseek( ), ftell( ), and rewind( ) to determine or change the location of the file position marker. The function fseek( ) resets the file position marker, in the file pointed to by pf, to the number of ibytes from the beginning of the file (ifrom = 0), from the current location of the file position marker (ifrom = 1), or from the end of the file (ifrom = 2). C has predefined three constants that can also be used in place of the variable ifrom: SEEK_SET (offset from beginning-of-file), SEEK_CUR (current file marker position), and SEEK_END (offset from the end-of-file). The function fseek( ) will return zero if the seek is successful and EOF otherwise. The general syntax for the function fseek( ) looks like this:
fseek(pf,ibytes,ifrom);
The function ftell( ) returns the current location of the file position marker in the file pointed to by pf. This location is indicated by an offset, measured in bytes, from the beginning of the file. The syntax for the function ftell( ) looks like this:
long_variable=ftell(pf);
The value returned by ftell( ) can be used in a subsequent call to fseek( ).
The function rewind( ) simply resets the file position marker in the file pointed to by pf to the beginning of the file. The syntax for the function rewind( ) looks like this:
rewind(pf);
The following C program illustrates the functions fseek( ), ftell( ), and rewind( ):
/*
*   fseek.c
*   A C program demonstrating the use of fseek,
*   ftell, and rewind.
*   Copyright (c) Bill/Chris H. Pappas and William H. Murray, 1998
*/

#include <stdio.h>

void main( )
{
 FILE
*pf;
 char c;
 long llocation;

 pf=fopen(“test.dat”,"r+t");

 c=fgetc(pf);
 putchar(c);

 c=fgetc(pf);
 putchar(c);

 llocation=ftell(pf);
 c=fgetc(pf);
 putchar(c);

 fseek(pf,llocation,0);

 c=fgetc(pf);
 putchar(c);

 fseek(pf,llocation,0);
 fputc(‘E’,pf);

 fseek(pf,llocation,0);

 c=fgetc(pf);
 putchar(c);

 rewind(pf);

 c=fgetc(pf);
 putchar(c);
}
The variable llocation has been defined to be of type long. This is because C supports files larger than 64K. The input file TEST.DAT contains the string “ABCD”. After the program opens the file, the first call to fgetc( ) gets the letter “A” and then prints it to the video display. The next statement pair inputs the letter “B” and prints it.
When the function ftell( ) is invoked, llocation is set equal to the file position marker’s current location. This is measured as an offset, in bytes, from the beginning of the file. Since the letter “B” has already been processed, llocation contains a 2. This means that the file position marker is pointing to the third character, which is 2 bytes over from the first letter, “A”.
Another I/O pair of statements now reads the letter “C” and prints it to the video display. After the program executes this last statement pair, the file position marker is 3 offset bytes from the beginning of the file, pointing to the fourth character, “D”.
At this point in the program, the function fseek( ) is invoked. It is instructed to move location offset bytes (or 2 offset bytes) from the beginning of the file (since the third parameter to the function fseek( ) is a zero, as defined earlier). This repositions the file position marker to the third character in the file. The variable c is again assigned the letter “C”, and it is printed a second time.
The second time the function fseek( ) is invoked, it uses parameters identical to the first invocation. The function fseek( ) moves the pointer to the third character, “C” (2 offset bytes into the file). However, the statement that follows doesn’t input the “C” a third time, but instead writes over it with a new letter, “E.” Since the file position marker has now moved past this new “E,” to verify that the letter was indeed placed in the file, the function fseek( ) is invoked still another time.
The nest statement pair inputs the new “E” and prints it to the video display. With this accomplished, the program invokes the function rewind( ), which moves the pf back to the beginning of the file. When the function fgetc( ) is then invoked, it returns the letter “A” and prints it to the file. The output from the program looks like this:
ABCCEA
You can use the same principles illustrated in this simple character example to create a random-access file of records. Suppose you have the following information recorded for a file of individuals: social security number, name, and address. Suppose also that you are allowing 11 characters for the social security number, in the form ddd-dd-dddd, with the name and address being given an additional 60 characters (or bytes). So far, each record would be 11 + 60 bytes long, or 71 bytes.
All of the possible contiguous record locations on a random-access disk file may not be full; the personnel record needs to contain a flag indicating whether or not that disk record location has been used. This requires adding one more byte to the personnel record, bringing the total for one person’s record to 72 bytes, plus 2 additional bytes to represent the record number, for a grand total record byte count of 74 bytes. One record could look like the following:
1 U111-22-3333Linda Lossannie, 521 Alan Street, Anywhere, USA
Record 1 in the file would occupy bytes zero through 73; record 2 would occupy bytes 74 through 147; record 3, 148 through 221; and so on. If you use the record number in conjunction with the fseek( ) function, any record location can be located on the disk. For example, to find the beginning of record 2, use the following statements:
loffset=(iwhich_record - 1) * sizeof(stA_PERSON);
fseek(pfi,loffset,0);
Once the file position marker has been moved to the beginning of the selected record, the information at that location can either be read or written by using various I/O functions such as fread( ) and fwrite( ).
With the exception of the comment block delimiter symbols /* and */ and the header STDIO.H, the program just discussed would work the same in C++. Just substitute the symbol // for both /* and */ and change STDIO.H to IOSTREAM.H.
Using the Integrated Debugger
Try entering this next program and printing out the value stored in the variable stcurrent_person.irecordnum after you have asked to search for the 25
/*
*   rndacs.c
*   A C random access file program using fseek, fread,
*   and fwrite.
*   Copyright (c) Bill/Chris H. Pappas and William H. Murray, 1998
*/

#include <stdio.h>
#include <string.h>
#define iFIRST 1
#define iLAST 50
#define iSS_SIZE 11
#define iDATA_SIZE 60
#define cVACANT ‘V’
#define cUSED ‘U’

typedef struct strecord {
 int  irecordnum;
 char cavailable;             /
* V free, U used */
 char csoc_sec_num[iSS_SIZE];
 char cdata[iDATA_SIZE];
} stA_PERSON;

void main( )
{
 FILE
*pfi;
 stA_PERSON stcurrent_person;
 int i,iwhich_record;
 long int loffset;

 pfi=fopen(“A:\\sample.fil”,"r+");

 for(i = iFIRST; i <= iLAST; i++) {
   stcurrent_person.cavailable=cVACANT;
   stcurrent_person.irecordnum=i;
   fwrite(&stcurrent_person,sizeof(stA_PERSON),1,pfi);
 }
 printf(“Please enter the record you would like to find.”);
 printf(“\nYour response must be between 1 and 50: ”);
 scanf(“%d”,&iwhich_record);

 loffset=(iwhich_record - 1)
* sizeof(stA_PERSON);
 fseek(pfi,loffset,0);
 fread(&stcurrent_person,sizeof(stA_PERSON),1,pfi);

 fclose(pfi);
}
The typedef has defined stA_PERSON as a structure that has a 2-byte irecordnum, a 1-byte cavailable character code, an 11-byte character array to hold a csoc_sec_num number, and a 60-byte cdata field. This brings the total structure’s size to 2 + 1 + 11 + 60, or 74 bytes.
Once the program has opened the file in read-and-update text mode, it creates and stores 50 records, each with its own unique irecordnum and all initialized to cVACANT. The fwrite( ) statement wants the address of the structure to output, the size in bytes of what it is outputting, how many to output, and which file to send it to. With this accomplished, the program next asks the user which record he or she would like to search for.
Finding the record is accomplished in two steps. First, an offset address from the beginning of the file must be calculated. For example, record 1 is stored in bytes zero to 73, record 2 is stored in bytes 74 to 148, and so on. By subtracting 1 from the record number entered by the user, the program multiplies this value by the number of bytes occupied by each structure and calculates the loffset. For example, finding record 2 is accomplished with the following calculation: (2 - 1) 74. This gives the second record a starting byte offset of 74. Using this calculated value, the fseek( ) function is then invoked and moves the file position marker loffset bytes into the file.
As you are tracing through the program asking to view records 1 through 10, all seems fine. However, when you ask to view the 11th record, what happens? You get garbage. The reason for this is that the program opened the file in text mode. Records 1 through 9 are all exactly 74 bytes, but records 10 and up take 75 bytes. Therefore, the 10th record starts at the appropriate loffset calculation, but it goes 1 byte further into the file. Therefore, the 11th record is at the address arrived at by using the following modified calculation:
loffset=((iwhich_record - 1) * sizeof(stA_PERSON)) + 1;
However, this calculation won’t work with the first nine records. The solution is to open the file in binary mode:
pfi=fopen(“A:\\sample.fil”,"r+b");
In character mode, the program tries to interpret any two-digit number as two single characters, increasing records with two-digit record_numbers by 1 byte. In binary mode, the integer record_number is interpreted properly. Exercise care when deciding how to open a file for I/O.

Books24x7.com, Inc 2000 –  


Visual C++ 6(c) The Complete Reference
Visual Studio 6: The Complete Reference
ISBN: B00007FYGA
EAN: N/A
Year: 1998
Pages: 207

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net