DEV Community

mikkel250
mikkel250

Posted on

Reading file contents in C

Overview

There are a number of functions in the standard library for reading the contents of a file, some that read individual characters, and others that will read strings. The more efficient and useful of the two will be the ones dealing with strings, but the functions that deal with characters will be covered first because there are situations in which reading specific characters may be preferred. These functions are intended to work in conjunction with files that have been already been opened by fopen(), which returns a pointer, and thus take a file pointer as an argument.

Reading characters from files with "file get character" function fgetc()

The fgetc() function takes a file pointer as an argument, and reads a single character from a file. After reading the character, the file pointer is advanced to next character. It will read newline characters as well. If pointer is at end of file, or if an error occurs, EOF is returned by this function.
Note: the return type of is int (not char), so it is recommended to assign the returned values of these functions to an integer type variable. See this for more details.

// Syntax
char *fgetc(FILE *pointerToFileToBeRead);
Enter fullscreen mode Exit fullscreen mode

To use the function in practice, the following example demonstrates basic usage and recommended practices (e.g. validity checks).

#include <stdio.h>

int main()
{
  // pointer to the file to be read
  FILE *filePointer = NULL;

  // declare an int to hold the value of the current character being read
  int thisCharacter;

  // open the file to be read, in read mode "r"
  filePointer = fopen("test-fgetc.txt", "r");

  // check the result of opening the file for errors
  if (filePointer == NULL)
  {
    // perror displays the system error message after whatever text is in the parentheses
    perror("Error: ");
    return (-1);
  }

  // read a single char in for each loop iteration
  while ((thisCharacter = fgetc(filePointer)) != EOF)
  {
    //print the character to a string
    printf("%c", thisCharacter);
  }

  // close the file
  fclose(filePointer);

  // set the pointer to null to reset it and free the memory
  filePointer = NULL;

  return 0;
}
Enter fullscreen mode Exit fullscreen mode

The comments in the code above hopefully make it clear what is happening.

The complementary function for writing characters to files is fputc().

Reading strings from files with "file get string" - fgets()

To read files, use fgets(), which I read in my mind as "file get string".
A simplified explanation is that it reads text from a file until is hits the newline character. In other words, it will read one line from a file at a time.

The more complete explanation is that the fgets() function will read in the entire string up until the 'new line' \n character, null terminator (aka 'end of string') character \0, EOF, or the number of user-specified characters (passed in as one of the arguments) is reached - whichever one of these happens first. An area of memory to store the data that is read by fgets() should be created prior to calling the function, which will be where the data read by the function is stored.

It takes 3 arguments: a pointer to a character array where the data that is read will be stored, the maximum number of characters to read in (an int, including the terminating null-character), and a pointer to the file to be read.
It will return the first argument (the string that was read in).
An error or EOF encountered will return NULL from the function.

A null terminator will be added to the end of the string by the function, so bear this in mind when allocating space for the first two arguments.

Note that this function will work with any stream (i.e. it can be used to store any received data such as user input or API calls), but for simplicity I'm sticking to only reading files. If you're not familiar with the concept of streams in C, it's worth doing some research.

Syntax:

fgets(char *stringToStoreDataThatIsRead, int numberOfCharsToRead, FILE *fileToBeRead);
Enter fullscreen mode Exit fullscreen mode

How it is used:

#include <stdio.h>

int main()
{
  // create the pointer to the file to be read
  FILE *filePointer = NULL;

  // create the character array (aka string) to store the data that is read
  char savedString[61];

  filePointer = fopen("testFile.txt", "r");

  // check there is no error opening the file
  if (filePointer == NULL)
  {
    perror("Error: ");
    return(-1);
  }

  if(fgets(savedString, 60, filePointer) != NULL) {
    // print the return value (aka string read in) to terminal
    printf("%s", savedString);
  }

  fclose(filePointer);
  filePointer = NULL;

  return 0;
}
Enter fullscreen mode Exit fullscreen mode

There is also the function gets(), but is not considered as safe to use as fgets(), and so it will not be covered.
The complementary function for writing to files is fputs().

Reading formatted input from a file

To get formatted input from a file, there is a an fscanf() function that works like scanf() for files. It takes any number of arguments: starting with the file to search, and then a list of any number of formats to check. It returns the number of input items successfully matched and assigned. If the operations complete successfully, it will return the integer 1.
The syntax is:

int fscanf(FILE *fileToCheck, const char *firstFormatToLookFor, *secondFormatToLookFor, ...etc);
Enter fullscreen mode Exit fullscreen mode

The example below reads a file and checks each string separated by whitespace (i.e. each word) in the format specified:
Let's assume the file, "names.txt", is a list of names, as below:

Names
Joe
Bob
Sally
Enter fullscreen mode Exit fullscreen mode

Using a loop in the example below will continue reading the file until the EOF is reached, which returns a value of 1 (an integer) after each success. When it fails or reaches the end of the file, it will return EOF or -1. So, the condition in the while loop below is like saying "while it keeps returning success, keep trying to scan the file, and break out of the loop when it fails."

#include <stdio.h>
#include <stdlib.h>

int main()
{
  // create a character array (i.e. string) to hold the values from fscanf()
  char *thisString[50];

  // create a pointer to the file that will be opened
  FILE *filePointer = NULL;

  // assign the pointer to the result of opening the file with fopen()
  filePointer = fopen("names.txt", "w+");

  // check there are no errors when opening the file
  if (filePointer != NULL)
  {
    // check the file and print out the result
    while (fscanf(filePointer, "%s", thisString) == 1)
    {
      printf("%s \n", thisString);
    }
  }

  fclose(filePointer);
  filePointer = NULL;

  return 0;
}
Enter fullscreen mode Exit fullscreen mode

Many of the examples I came across made use of unfamiliar syntax, so I tried to use the simplest one I could above that also seemed to convey both how it's used, and a real use case. Feel free to let me know if it's not clear in the comments.

Many would also make use of another syntax that will be handy to know when scanning files, the %*s. Including the asterisk before the 's' means "ignore this string and move on to the next." So if you had a list of users first names, last names, and ages, separated by spaces:

Joe Blow 25
Jane Doe 35
Luke Skywalker 62
Enter fullscreen mode Exit fullscreen mode

If you wanted to save only the numbers, you could pluck out the third item in each line using the following syntax with fscanf(), and assign it to an int:

// create a variable (and space in memory) to hold the integer age
int age;

// note that the 'address of' operator is used since we are getting integers,
// which are handled differently than strings
fscanf("%*s %*s %d", &age);
printf("%d", age);

/*
output:
25
35
62
*/

Enter fullscreen mode Exit fullscreen mode

Both fgets() and fscanf() are somewhat complicated functions, so using them yourself, researching, and reading more is recommended, as this just scratches the surface of how they can be used.

Top comments (0)