Learn C - C File






C programmers use pointers to manage streams for reading and writing data.

Streams are just file or hardware devices, such as a monitor or printer.

To point to and manage a file stream in C, use a data structure called FILE.

Pointers of type FILE are created just like any other variable.

#include <stdio.h> 
int main(void) { 
   //create 3 file pointers 
   FILE *pRead; 
   FILE *pWrite; 
   FILE *pAppend; 
   
   return 0;
} //end main 

The code above created three FILE pointer variables called pRead, pWrite, and pAppend.

Each FILE pointer can open and manage a separate data file.





Opening and Closing Files

The basic components for file processing are opening, processing, and closing data files.

Opening a file should have error checking and/or handling.

Failure to test the results of a file-open will cause unwanted program results.

To open a data file, use the standard input/output library function fopen().

The fopen() function returns a FILE pointer to a FILE pointer.


#include <stdio.h> 
main() 
{ 
   FILE *pRead; 
   pRead = fopen("file1.dat", "r"); 
} //end main  

This program uses the fopen() function to open a data file, called file1.dat, in a read-only manner.

The fopen() function returns a FILE pointer back to the pRead variable.

The fopen() function takes two arguments: the file name, and the second argument tells fopen() how to open the file.

The following table lists a few common options for opening text files using fopen().

ModeDescription
rOpens file for reading
wCreates file for writing; discards any previous data
aWrites to end of file (append)

The code above generates the following result.





Open File Example

After opening a file, you should ensure that the FILE pointer was returned successfully.

To test fopen()'s return value, test for a NULL value in a condition, as demonstrated next.


#include <stdio.h> 
main() //from  ww  w.  j a  v  a 2  s .  c om
{ 
   FILE *pRead; 
   pRead = fopen("file1.dat", "r"); 
   if ( pRead == NULL ) 
      printf("\nFile cannot be opened\n"); 
   else 
      printf("\nFile opened for reading\n"); 
} //end main 

The following condition

if ( pRead == NULL )

can be shortened with the next condition.

if ( pRead ) 

If pRead returns a non- NULL, the if condition is true. If pRead returns NULL, the condition is false.

After successfully opening and processing a file, you should close the file using a function called fclose().

The fclose() function uses the FILE pointer to flush the stream and close the file.

The fclose() function takes a FILE pointer name as an argument.

fclose(pRead);

The code above generates the following result.

Reading Data

The following code shows how to read a file's contents and check for the file's EOF (end-of-file) marker using the functions fscanf() and feof().

The following program that reads a data file called names.dat until an end-of-file marker is read.


#include <stdio.h> 
main() //from  www. j a  v a 2 s.  c  o  m
{ 
   FILE *pRead; 
   char name[10]; 
   pRead = fopen("names.dat", "r"); 
   if ( pRead == NULL ) 
      printf("\nFile cannot be opened\n"); 
   else 
      printf("\nContents of names.dat\n\n"); 
   fscanf(pRead, "%s", name); 
   while ( !feof(pRead) ) { 
         printf("%s\n", name); 
         fscanf(pRead, "%s", name); 
   }  //end loop 
} //end main 

After successfully opening names.dat, I use the fscanf() function to read a single field within the file.

The fscanf() function is similar to the scanf() function but works with FILE streams.

It takes three arguments: a FILE pointer, a data type, and a variable to store the retrieved value.

After reading the record, the printf() function displays data from the file.

To read multiple records, use a looping that can read all records until a condition is met.

To read all records until the end-of-file is met, use the feof() function.

Using the not operator (!), you can pass the FILE pointer to the feof() function and loop until the function returns a non-zero value when an end-of-file marker is reached.

fscanf() can also read records containing multiple fields by supplying to the second argument a series of type specifiers for each field in the record.

For example, the next fscanf() function expects to read two character strings called name and hobby.

fscanf(pRead, "%s%s", name, hobby);

The %s type specifier will read a series of characters until a white space is found, including blank, new line, or tab.

Other valid type specifiers for the fscanf() function are listed in Table 11.3.

TypeDescription
cSingle character
dDecimal integer
e, E, f, g, GFloating point
oOctal integer
sString of characters
uUnsigned decimal integer
x, XHexadecimal integer

The code above generates the following result.

Example multiple fields

The following code shows how to read multiple fields.


#include <stdio.h> 
main() //from   w  ww.  ja v  a 2 s.  co  m
{ 
   FILE *pRead; 
   char name[10]; 
   char hobby[15]; 
   pRead = fopen("hobbies.dat", "r"); 
   if ( pRead == NULL ) 
      printf("\nFile cannot be opened\n"); 
   else 
      printf("\nName\tHobby\n\n"); 

   fscanf(pRead, "%s%s", name, hobby); 
   while ( !feof(pRead) ) { 
         printf("%s\t%s\n", name, hobby); 
         fscanf(pRead, "%s%s", name, hobby); 
   }  //end loop 
} //end main 

The code above generates the following result.

Writing Data

The fprintf() function takes a FILE pointer, a list of data types, and a list of values to write information to a data file.

Example

By separating each field in the record with a tab, I can easily read the same record back with the following program.


#include <stdio.h> 
main() // w w w . j  a v a 2 s.  co m
{ 
   FILE *pRead; 
   char fName[20]; 
   char lName[20]; 
   char id[15]; 
   float gpa; 
   pRead = fopen("students.dat", "r"); 
   if ( pRead == NULL ) 
      printf("\nFile not opened\n"); 
   else { 
      //print heading 
      printf("\nName\t\tID\t\tGPA\n\n"); 
      //read field information from data file and store in variables 
      fscanf(pRead, "%s%s%s%f", fName, lName, id, &gpa); 
      //print variable data to standard output 
      printf("%s %s\t%s\t%.2f\n", fName, lName, id, gpa); 
      fclose(pRead); 
   }  //end if 
} //end main  

Opening a data file using fopen() with a w argument value will erase any previous data stored in the file.

Use the a attribute to append data at the end of the file.

The code above generates the following result.

Appending Data

Appending information to a data file involves opening a file for writing using the a attribute in fopen() and writing data to the end of an existing file.

If the file does not exist, however, a new data file is created as specified in the fopen() statement.

The following code demonstrates appending records to an existing data file.


#include <stdio.h> 
void readData(void); 
main() //  w w  w .  j  a v a 2s . c om
{ 
   FILE *pWrite; 
   char name[10]; 
   char hobby[15]; 
   printf("\nCurrent file contents:\n"); 
   readData(); 
   printf("\nEnter a new name and hobby: "); 
   scanf("%s%s", name, hobby); 
   //open data file for append 
   pWrite = fopen("hobbies.dat", "a"); 
   if ( pWrite == NULL ) 
      printf("\nFile cannot be opened\n"); 
   else { 
      //append record information to data file 
      fprintf(pWrite, "%s %s\n", name, hobby); 
      fclose(pWrite); 
      readData(); 
   }  //end if 
} //end main 

void readData(void) 
{ 
   FILE *pRead; 
   char name[10]; 
   char hobby[15]; 
   //open data file for read access only 
   pRead = fopen("hobbies.dat", "r"); 
   if ( pRead == NULL ) 
      printf("\nFile cannot be opened\n"); 
   else { 
      printf("\nName\tHobby\n\n"); 
      fscanf(pRead, "%s%s", name, hobby); 
      //read records from data file until end of file is reached 
      while ( !feof(pRead) ) { 
         printf("%s\t%s\n", name, hobby); 
         fscanf(pRead, "%s%s", name, hobby); 
      } 
   }
   fclose(pRead); 
} //end readData 

The code above generates the following result.

Example 2

The following code uses goto and a couple of new functions (perror() and exit()) to build error handling into a file I/O program.


#include <stdio.h> 
#include <stdlib.h> 
main() { /*ww  w  .j a v a 2 s  .  c o m*/
   FILE *pRead; 
   char name[10]; 
   char hobby[15]; 
   pRead = fopen("hobbies.dat", "r"); 
   if ( pRead == NULL ) 
      goto ErrorHandler; 
   else { 
      printf("\nName\tHobby\n\n"); 
      fscanf(pRead, "%s%s", name, hobby); 
      while ( !feof(pRead) ) { 
         printf("%s\t%s\n", name, hobby); 
         fscanf(pRead, "%s%s", name, hobby); 
      }  //end loop 
   } // end if 
   exit(EXIT_SUCCESS); //exit program normally 
   ErrorHandler: 
        perror("The following error occurred"); 
        exit(EXIT_FAILURE); //exit program with error 

} //end main 

The exit() function, part of the <stdlib.h> library, terminates a program as if it were exited normally.

As shown next, the exit() function is common with programmers who want to terminate a program when encountering file I/O (input/output) errors.

exit(EXIT_SUCCESS); //exit program normally

or

exit(EXIT_FAILURE); //exit program with error 

The exit() function takes a single parameter, a constant of either EXIT_SUCCESS or EXIT_FAILURE, both of which return a pre-defined value for success or failure, respectively.

The perror() function sends a message to standard output describing the last error encountered.

The perror() function takes a single string argument, which is printed first, followed by a colon and a blank, then the system generated error message and a new line.

perror("The following error occurred");

The code above generates the following result.