File Input / Output in C can be achieved using the C stream functions such as fopen, fclose or using system calls of open, close. Depending on which method you choose, the functions available for reading, creating, and writing to that file differ. In this article I will tackle the use of the C stream function set.
Opening a File in C using fopen
The fopen() function call takes two arguments, one of the file path, and the second the mode in which you want to open that file. The mode is especially important, the options include:
Note: This is extracted from the glibc manual page.
- r – Open text file for reading. The stream is positioned at the beginning of the file.
- r+ – Open for reading and writing. The stream is positioned at the beginning of the file.
- w – Truncate file to zero length or create text file for writing. The stream is positioned at the beginning of the file.
- w+ – Open for reading and writing. The file is created if it does not exist, otherwise it is truncated. The stream is positioned at the beginning of the file.
- a – Open for appending (writing at end of file). The file is created if it does not exist. The stream is positioned at the end of the file.
- a+ – Open for reading and appending (writing at end of file). The file is created if it does not exist. The initial file position for reading is at the beginning of the file, but output is always appended to the end of the file.
So for example, if you have a file that you know already exists on disk, you can open it by doing:
#define FILEPATH "/tmp/erik_file.txt"
FILE *fp; // fopen returns a file handle of type FILE *
fp = fopen(FILEPATH, "r"); // in this case we open the file for reading
if(!fp){
fprintf(stderr, "File - %s - could not be opened.\n", FILEPATH);
return -1;
}
// Do some processing on the file..perhaps read from it
fgets(s,size,fp);
If the file cannot be opened then fopen() will return NULL with errno being set. Otherwise fopen() returns a valid file pointer.
How To Read From a File in C
Now we have our file opened from the above example, but what good is an open file if you don’t do anything with it? Since we have a file stream open there are various function calls we can use that take a FILE stream as a parameter.
Note: Extracted from glibc manual pages.
- int fgetc(FILE *stream);
fgetc() reads the next character from stream and returns it as an unsigned char cast to an int, or EOF on end of file or error. - char *fgets(char *s, int size, FILE *stream);
reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A \0 is stored after the last character in the buffer. - int getc(FILE *stream);
is equivalent to fgetc() except that it may be implemented as a macro which evaluates stream more than once. - int ungetc(int c, FILE *stream);
pushes c back to stream, cast to unsigned char, where it is available for subsequent read operations. Pushed-back characters will be returned in reverse order; only one pushback is guaranteed.
For example:
#define MAX_LEN 512
...
char data[MAX_LEN];
while (fgets(data, MAX_LEN, fp) != NULL) { // We read input up to MAX_LEN size.
...
}
// do something with 'data'.
How To Write To a File in C
To write to a file in C, the file must have been opened with the ‘r+’ or ‘w+’ options in fopen(), otherwise the user will not have the ability to write to the file. Lets write the file using fwrite(). fwrite() is used for writing binary data to the file.
- size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
So if we wanted to write ‘hello’ to the file, assuming it is already open, we can simply do:
int count = 0;
const char *str = "hello\n";
// write to the file, and get return value of bytes written
count = fwrite(str, strlen(str), 1, fp);
// display bytes written and whether it was a success
// then close the file
printf("Wrote %u bytes. fclose(fp) %s.\n", count, fclose(fp) == 0 ? "succeeded" : "failed");
return EXIT_SUCCESS;
Closing a File in C
To close the file that was previously opened using fopen(), simply call fclose() passing in the FILE *fp that you used earlier during the open procedure.
fclose(fp);
Useful File Pointer Functions in C
I always find it handy to be able to move to a specific position in a file for reading or writing. It is also sometimes useful to know where in a certain file your pointer is, these functions do just that.
- int fseek(FILE *stream, long offset, int whence);
- long ftell(FILE *stream);
- void rewind(FILE *stream);
- int fgetpos(FILE *stream, fpos_t *pos);
- int fsetpos(FILE *stream, fpos_t *pos);
Note: Extracted from glibc manual pages.
The fseek() function sets the file position indicator for the stream pointed to by stream. The new position, measured in bytes, is obtained by adding offset bytes to the position specified by whence. If whence is set to SEEK_SET, SEEK_CUR, or SEEK_END, the offset is relative to the start of the file, the current position indicator, or end-of-file, respectively. A successful call to the fseek() function clears the end-of-file indicator for the stream and undoes any effects of the ungetc(3) function on the same stream.
The ftell() function obtains the current value of the file position indicator for the stream pointed to by stream.
The rewind() function sets the file position indicator for the stream pointed to by stream to the beginning of the file. It is equivalent to:
(void)fseek(stream, 0L, SEEK_SET)
except that the error indicator for the stream is also cleared (see clearerr(3)).
The fgetpos() and fsetpos() functions are alternate interfaces equivalent to ftell() and fseek() (with whence set to SEEK_SET), setting and storing the current value of the file offset into or from the object referenced by pos. On some non-UNIX systems an fpos_t object may be a complex object and these routines may be the only way to portably reposition a text stream.