File Input and Output 

Creating and linking a stream to a disk file is called opening a file. When a file is opened, it is available to the OS for reading, writing or both.

Opening a File with fopen()

The fopen() library function is used to open a file:

FILE *fopen(const char *filename, const char *mode);

The fopen call will initialise a structure of type FILE, which contains all the information necessary to control the stream and return a pointer to that structure. This pointer is used in all subsequent operations on the file. If fopen() fails, it returns NULL. 

The parameter filename contains the name and address of the file to be opened. The filename argument can be a literal string enclosed in double quotation marks or a pointer to a string variable. The parameter mode specifies the mode in which to open the file. The file may be binary or text and maybe opened for reading, writing, or both.  Values of mode for the fopen() function are listed below.

Sr.No. Mode & Description
r Opens an existing text file for reading.
w Opens a text file for writing. If it does not exist, then a new file is created. Here your program will start writing content from the beginning of the file.
a Opens a text file for writing in appending mode. If it does not exist, then a new file is created. Here your program will start appending content in the existing file content.
r+ Opens a text file for both reading and writing.
w+ Opens a text file for both reading and writing. It first truncates the file to zero length if it exists, otherwise creates a file if it does not exist.
a+ Opens a text file for both reading and writing. It creates the file if it does not exist. The reading will start from the beginning but writing can only be appended.


A failure to open a file will see fopen return NULL. Errors may be caused by factors such as an invalid filename or a nonexistent location 

Closing a File

To close a file, use the fclose( ) function. The prototype of this function is −

int fclose( FILE *fp );

The fclose() function returns zero on success, or EOF if there is an error in closing the file. When a file is closed, the file’s buffer is flushed (written to the disk) and the memory is released.

Writing to a File.

Data can be written to a disk file in three ways:

  • Using formatted data files. 
  • Using character output to save single characters or lines of characters to a file. 
  • Using direct output.

Unformatted Output with fputc

Writes a character to the stream and moves the position indicator forward. The prototype of fputc is −

int fputc( int c, FILE *fp );
int fputs( const char *s, FILE *fp );

The function fputc() writes the character value c or the string s to the output stream referenced by fp.
If successful it returns the written character written or EOF if there is an error. The character is written at the position indicated by the internal position indicator of the stream, which is then automatically advanced by one.

Formatted Output using fprintf

Formatted file output is done with the library function fprintf() . The prototype of fprintf() is-

int fprintf ( FILE * stream, const char * format, ... );

The first parameter is a pointer to type FILE. To write data to a storage location, use the pointer returned with the fopen() call.  The second argument is the format string. The format string used by fprintf() follows the same format as printf(). In the function prototype, ellipses represent a variable number of additional arguments.

Direct Output with fwrite

The fwrite() function is used to write records (a sequence of bytes)  to the output stream. These records may be such things as arrays and structures. The syntax of fwrite() function is as follows 

fwrite( ptr, int size, int n, FILE *fp );

The fwrite() function accepts four arguments.  
ptr points to the block of memory which contains the data items to be written.
size specifies the number of bytes of each item to be written.
n is the number of items to be written.
FILE* is a pointer to the file where data items will be written in binary mode.

When the code below is compiled and executed, it creates a new file test.txt in the //home directory on a linux system and writes two lines.

#include <stdio.h>
main() {
   FILE *fp;
   fp = fopen("//home/m/test.txt", "w+");
   fprintf(fp, "create output file...\n");
   fputs("Use fputs file...\n", fp);
   fclose(fp);
}

Reading from a file

Unformatted Input with fgetc

The fgetc() function reads a character from the input file referenced by fp.  It returns the character read or EOF on reaching the end of the file. The prototype of fgetc() is-

int fgetc( FILE * fp );

The function fgets() reads up to n-1 characters from the input stream referenced by fp. The following string reads an input string into the buffer ibuf, appending a null character to terminate the string.

char *fgets( char *ibuf, int n, FILE *fp ); 

Formatted File Input with fscanf 

The fscanf() function reads formatted input from a file. The prototype of fscanf() is- 

int fscanf(FILE *fp, const char *fmt, ...);

The parameter fp is a pointer to type FILE returned by fopen(). The parameter fmt is a pointer to the format string that specifies how fscanf() is to read the input. Finally, the ellipses ( ... ) indicate one or more additional arguments.

Direct Input with the fread() 

The fread() function is used to read binary data and is complementary to fwrite(). The function prototype is as follows

fread( ptr, int size, int n, FILE *fp );

The fread() function accepts four arguments. 

ptr is the address of the memory block where data is stored after reading. 
size specifies the number of bytes of each item to be read. 
n is the number of items read from the file where each item occupies the number of bytes specified in the second argument.
FILE* is the file from where the data is read in binary mode.

On success, it reads n items from the file and returns n. On error or end of the file, it returns a number less than n.

The position indicator of the stream is advanced by the total amount of bytes read.

The total amount of bytes read if successful is (size*count).

#include <stdio.h> 
int main () 
{
char str1[20];
FILE * fp;
fp = fopen ("file.txt", "w+");
fputs("output_file", fp);
rewind(fp);
fscanf(fp, "%s", str1);
printf("%s\n", str1 );
fclose(fp);
return(0);
}

Sequential Versus Random File Access

Every file IO operation has a position indicator indicating where data is read from and written to. The position is always given in terms of bytes from the beginning of the file.   When the data in a file is read or written sequentially the file indicator position is taken care of automatically.

Manual control over the file position indicator is known as random file access. This means that the programmer can read data from or write data to any position in a file without reading or writing all the preceding data. 

ftell() and rewind() 

To move the position indicator to the beginning of a file, use the function rewind(). The prototype  is

void rewind(FILE *fp);

The parameter fp is the FILE pointer associated with the stream. After calling rewind() the file’s position indicator is set to the beginning of the file (byte 0). 

To determine the value of a file’s position indicator, use function ftell(). The prototype is

long ftell(FILE *fp);

The argument fp is the FILE pointer returned by fopen(). ftell() returns a type long that gives the current file position in bytes from the
start of the file (the first byte is at position 0). If an error occurs, ftell() returns -1L

fseek()  

fseek()  sets the position of file indicator to anywhere in the file. The function prototype is

int fseek(FILE *fp, long offset, int origin);

The argument fp is the FILE pointer associated with the file. The distance to move the position indicator is given by offset in bytes, the argument origin specifies the move’s relative starting point.

There can be three values for origin. The symbolic constants are defined in io.h

SEEK_SET 0 - Moves the indicator offset bytes from the beginning of the file.
SEEK_CUR 1 - Moves the indicator offset bytes from its current position.
SEEK_END 2 - Moves the indicator offset bytes from the end of the file.

#include <stdlib.h>
#include <stdio.h>
#define BUFLEN 6
char readdate[] = "abcdefghijklmnopqrstuvwxyz";
int main( void )
{
FILE *fp;
char buf[2];
if ( (fp = fopen("random.TXT", "w")) == NULL)
{
fprintf(stderr, "Error opening file.");
exit(1);
}
if (fputs(readdate, fp) == EOF)
{
fprintf(stderr, "Error writing to file.");
exit(1);
}
fclose(fp);
if ( (fp = fopen("random.TXT", "r")) == NULL)
{
fprintf(stderr, "Error opening file.");
exit(1);
}
printf("\nAfter opening the file the file pointer is at position = %ld", ftell(fp));
fgets(buf,2, fp);//read first character
printf("\nThe character at position zero is %s",buf);
printf("\nNow the file pointer is at position = %ld", ftell(fp));
fseek(fp, 10, 0);//move to pointer to position 10
printf("\nMove position marker to position 10");
fgets(buf,2, fp);
printf("\nThe character at position 5 is %s",buf);
printf("\nMove position marker to start of file");
rewind(fp);//move file pointer to start of file
printf("\nNow the file pointer is at the start of the file = %ld", ftell(fp));
fgets(buf,2, fp);
printf("\nThe current character is = %s", buf);
fclose(fp);
return 0;
}

Detecting the End of a File

There are two ways to detect end-of-file.

Detecting EOF character -  When a character input function reads the EOF this indicates the end of the file

Checking FEOF character -  The function feof() returns 0 if the end of file fp hasn’t been reached, or a nonzero value if end-of-file has been reached. 

File Management Functions

Deleting a File

To delete a file use the function remove(). The prototype is  

int remove( const char *filename );

The variable *filename is a pointer to the file name to be deleted. If the file exists, it is deleted and the remove function returns 0. If the user does not have sufficient access rights, does not exist or is already open then the delete operation will fail returning -1. 

Renaming a File

The rename() function changes the name of an existing disk file. The prototype is

int rename( const char *oldname, const char *newname );

The function returns 0 on success, or -1 if an error occurs. For the function to work the old filename must exist and the new filename must not exist. Both files must be on the same disk.

Temporary Files Names

A temporary file is a file that is created and used by the program during program execution and then deleted before the program terminates.  The function tmpnam() returns a string containing a unique file name suitable to safely use without risking overwriting any existing files. The prototype is as follows:

char *tmpnam(char *f);

The parameter f must be a pointer to a buffer large enough to hold the filename. A null pointer ( NULL ), means the temporary name is stored in the tmpnam() buffer.  The function returns a pointer to that buffer.

#include <stdio.h>
int main( void )
{
char temp[20], *t;
tmpnam(temp);/* create temporary name and store in temp buffer. */
t = tmpnam(NULL);/* create another name, this time in the function’s internal buffer */
/* Display the names. */
printf("Temporary name 1: %s", temp);
printf("\nTemporary name 2: %s\n", t);
return 0;
}