File Processing

It is very common to read input from users or files. Both can be performed using fgets, which is a safe library function. This document starts with fgets, which can be used in any circumstance. It also presents using fscanf, which can only be used on well-formed, numeric data. You should never switch off between fgets and fscanf, because there are subtle challenges in passing off between the two. Outline:
Click here for the full program code of these examples, not just a snippet.

Reading in a Text File

The most flexible approach is to read in a line as characters. A line is defined as a sequence of characters ended by the '\n' character. Once read in, the line is parsed, or divided into tokens - short text strings that are meaningful. For example, if you were reading in a document of text, you might split it into sentences, then words and punctuation. Each word and punctuation character would be a token. Here is the function prototype of fgets.
char *fgets(char *s, int size, FILE *stream);
What does fgets do? How do you use fgets? The trick is that all three input parameters need to have been set properly. To read from a file, you need to use the following function to open it:
FILE *fopen(const char *restrict pathname, const char *restrict mode)
What does fopen do? How do you use fopen to read from a file?

Examples

Example 1: Read from the user and print out back to them.
char buffer[500];

// read in the line and make sure it was successful
// just for fun, let's read in 10 inputs from the user
int i;
for(i=0;i<10;i++)
{
   // read in and check whether read was successful
   if (fgets(buffer,500,stdin) != NULL)
   {
	printf("You inputted %s!\n",buffer);
   }
}

Example 2: Read a filename from the user, use that to open a file and print it out.

char buffer[500];
FILE *infile;
int len;

fgets(buffer,500,stdin);
// remove the '\n' at the end of the line
len = strlen(buffer);
buffer[len-1] = '\0'; // replace '\n' with '\0' to shorten line by 1.

// open the file
if ((infile = fopen(buffer,"r")) == NULL)
{
	printf("Could not open %s\n", buffer);
	exit(1);
}

// while not end of the file
while (!feof(infile))
{

	// read in the line and make sure it was successful
	if (fgets(buffer,500,infile) != NULL)
	{
		// print out the line
		printf("%s", buffer);
	}

}
// don't forget to close the file when you're done
fclose(infile);

Parsing Input

Remember that in C, strings are nothing more than a character array followed by a '\0' character. So you should always think of strings in this way.

strtok is a string tokenizer, which, like fgets, is general functionality provided in some way by pretty much every programming language. The idea is that you tell the tokenizer what string you want to split up and by what delimiters you want it split up, and it will give you each token. There were several new vocabulary words in that sentence, so let me give you a concrete example.

"This is a sentence, and I want to read only the words from this sentence.\n"

In the above case, the delimiters are spaces, commas, periods, and \n. In the above case, the tokens are "this", "is", "a", "sentence", etc. Each word is a token.

So the job of the string tokenizer is to, given the knowledge that you want it to split by commands, periods, spaces, and \n, give you, in sequence, the different words.

char *strtok(char *string, char *deliminators);
What does strotok do?
If you provide a pointer to a string as the first parameter:
  1. Start at the beginning of the string.
  2. Advances to the first instance of an item that is not a delimiter.
  3. Finds the first instance of a deliminator and replaces it with '\0'.
  4. Returns a pointer to the location it found in step (2).
  5. Once it runs out of tokens in the string, it returns NULL.

If you use NULL as the first parameter:
  1. Start immediately after the '\0' in the previous call to strtok. (We will learn later how to do that)
  2. Advances to the first instance of an item that is not a delimiter.
  3. Finds the first instance of a deliminator and replaces it with '\0'.
  4. Returns a pointer to the location it found in step (2).
  5. Once it runs out of tokens in the string, it returns NULL.
  6. The result is that the original string has been modified from its original form. How do you use strtok?
    char str[] = "This is a sentence, and I want to read only the words from this sentence.\n";
    
    char *tokenPtr;
    
    // initialize the string tokenizer by passing in str
    // capture the return value in tokenPtr.
    tokenPtr = strtok(str, " ,.\n");
    // check to make sure the previous call found a token.
    while(tokenPtr != NULL)
    {
    	// do something with the token.
    	printf("%s\n",tokenPtr);
    	// for all subsequent calls, use NULL as the first argument
    	tokenPtr = strtok(NULL, " ,.\n");
    }
    

    Reading in numbers

    Notice that with the pair of fgets and strtok, the token is a string. Often, however, you need the input to be a number. You can convert from a string to other types easily using some library calls.

    Integers:
    Floating-point Numbers:
    What these functions do:
    How to use them:
    char buffer[500];
    // read in a line from the user
    fgets(buffer,500,stdin);
    // I am expecting a base 10 integer, so I convert it:
    long choice = strtol(buffer, NULL, 10);
    // now I can use it as an integer!!!
    

    Reading in a well-formed numerical file

    Writing to a Text File

    Writing to a text file is almost identical to printing to the screen - the only difference is that you specify a file pointer.
            FILE *outfile;
            if ((outfile = fopen("outfilename.txt","w")) == NULL)
            {
                    printf("Could not open outfilename.txt\n");
                    return;
            }
    
    	// writing to a file is like writing to the screen - 
            // use fprintf rather than printf and give it the outfile first
    	fprintf(outfile, "I am writing to a file!!!\nLook at me!!\n");
    	fclose(outfile);