Erin's CS stuff

CS stuff!

File IO

So far, any information coming and going between our programs and the "outside world" have been related to the idea of a person using the program. While that's a very important source/destination to consider, there are plenty more! The first one we'll learn about is files

Since File IO is very similar to Formatted IO, it may help to review that topic before moving on.

One of the important technical details we skipped over when covering Formatted IO is streams. The term streams reflects an abstraction used to describe or imagine how information flows to and from the program. Since streams only flow in one direction, we tend to consider them in terms of input or output streams.

Syntax

In C, streams are implemented using a file pointer data type: FILE *. The input and output streams used for Formatted IO are called stdin and stdout. Since these always connect to the keyboard or screen as the source or destination respectively, they can be maintained by the stdio library and we don't have to add any special code to use them.

Files, on the other hand, are stored all over the hard drive so the information needed to connect to a file changes over time. This means we need to write code to create and use our own file pointers when we want to use File IO. Luckily, much of the code to create these file streams in our programs is pretty standard!

File IO starts with a file pointer declaration:
FILE* filePointer;

The fopen function is used to try to connect our file pointer to the file, thereby establishing the stream:
filePointer = fopen("filename.txt", "r");

The first argument is a string containing the filename (this is the only time the filename is used). The second argument is the mode, which determines which "direction" the stream flows (in or out). Although there are more modes, we will stick primarily to the following modes:

Mode Code Road
Read "r" get input info into the program from a file
Write "w" output info from the program to a file, starting at the file beginning
(any previous contents are erased)
Append "a" output info from the program to a file, starting at the file end
(any previous contents remain)

If it fails to connect to the file, the fopen function will return a NULL[1] pointer. Before we do anything with the stream or file pointer, we first have to check to see if the connection failed by checking the file pointer for NULL.

if(filePointer == NULL){ // unsuccessful connection
  printf("Could not open file.\n");
  // you must skip any further File IO code or...

  // you could even end the program
  return 0;
}

If the file pointer is not NULL, then you can continue on to do the actual reading from or writing to a file (covered in the Behavior section). When you are done with the file, you must close it by sending the file pointer as an argument into the fclose function.
fclose(filePointer);

Best practices often orgranize programs by putting the opening and closing of files in the main function, and passing the connected file pointer into a different function to do the actual File IO work. In that case our program looks a little something like this:

Behavior

Output

Once a stream or file pointer is successfully connected to a file in "w" mode, we can "output" or write to it. We primarily use the fprintf function for that. It is almost identical to printf with one exception... Can you find it?
fprintf(filePointer, "Hello World!\n");

Yep! A new argument goes before the format string: the file pointer!

Input

Once a stream or file pointer is successfully connected to a file in "r" mode, we can get "input" or read from it. We primarily use the fscanf function for that. It is almost identical to fscanf with the same exception as above: the file pointer is added!
fscanf(filePointer, "%s", firstName);

The same constraints apply to fscanf as scanf for strings: it stops at the first blank space. If we need more than that, we can always use the fgets function!
fgets(fullName, SIZE, filePointer);

We'll spend a lot of time in class going over examples, especially situations where we need to "read" multiple lines of data from a file and store that data into an array.

Metaphor

I've often used the process of making a phone call as a metaphor for some parts of File IO.

The file pointer is the phone and we have to get one first! Then, we have to use the fopen function which is a lot like dialing the phone number, especially because we only use the phone number once then we talk on the phone. It's the same with File IO: we only use the filename once, then we use the file pointer for the rest of the program.

It's also important we wait until the phone is connected before the conversation begins. If we don't connect then we can put the phone away. Same with File IO!

Finally, once we're done with the conversation we hang open the phone (or call the fclose function in File IO). We don't need to hange up if the call doesn't go through and sending a NULL pointer to the fclose function will cause a segmentation fault. Also, if we don't hang up then we can't make another call!

1. NULL is a commonly used label for the null pointer. It’s a lot like a default value for pointers when they’re not pointing at something.