File Input and Output,
fopen and fclose

Prev: Unions
Next: feof, fgets and fread



Streams Revisited and the FILE Structure

Try and cast your mind back to the Standard Input and Output section when I talked about stdin and stdout.

In C, stdin is the standard input file stream and refers to the keyboard.

scanf is the equivalent of fscanf, with the stream set to stdin by default. The same applies to the other input functions we've encountered: getc and gets are fgetc and fgets with the input stream set to stdin.

In this section, we'll be reading data from a file, not from stdin.

In stdio.h there is a defined structure called FILE.

For file input and output, we usually create variables of type FILE * to point to a file located on the computer.

We could pass a FILE pointer into an input or output function, for example, fscanf.



Using fopen To Open Files

First things first: we have to open a file to be able to do anything else with it.

For this, we use fopen. This function takes two arguments - the first one is the path to your file, including the filename. So if your file sits in the same directory as your C source file, you can simply enter the filename in here - this is probably the one you'll use most.

The second argument is another char *, and determines how the file is opened by your program.

There are 12 different values that could be used, and I will run through them throughout the File Input and Output sections.

Finally, fopen returns a FILE pointer if the file was opened successfully, else it returns NULL.



Using fclose To Close Files

When you've finished with a file, it's best if you closed it - seems logical enough!

Simply pass it a FILE pointer, but be warned, don't pass a NULL pointer (it points to nothing), or your program might crash.



Opening Files for Reading Only

Firstly, a text file is a file that you can open and read its contents visually - for example, C source files, .txt files, HTML etc - anything that looks "neat" in Notepad.

A binary file is a file that is written in machine code - usually seen as a mass of weird characters in Notepad! Examples are bitmaps, executables etc.

For these tutorials, we're going to be looking at standard text files. If you wanted to open a binary file, simply put a b at the end of the second argument of fopen.

To open a text file for reading only, pass "r" as the second argument of fopen, as demonstrated in this example:

#include <stdio.h>

int main() {
  FILE *file; /* declare a FILE pointer */

  file = fopen("data/hello.txt", "r"); 
  /* open a text file for reading */

  if(file==NULL) {
    printf("Error: can't open file.\n");
    /* fclose(file); DON'T PASS A NULL POINTER TO fclose !! */
    return 1;
  }
  else {
    printf("File opened. Now closing it...\n");
    fclose(file);
    return 0;
  }
}

Now, I created a file earlier in Notepad, named it "hello.txt" and put it in a folder called "data", which lives in the folder where my source code is kept.

I could've simply moved the file into the same directory as the source code, but I just wanted to demonstrate what you'd do if it was in a different directory.

Inside main, I created a FILE * called file. Afterwards, I call the fopen function, passing it the path to my text file, as well as "r" to let the program know that I'm only intending to read from the file.

Notice I assigned the function call to file. If the file was successfully opened, file would point to that file, else it'll point to nothing (a pointer that points to nothing is called a NULL POINTER).

Then I perform a check to see if file is a NULL pointer: if(file==NULL). If so, display an error message, and quit the program by returning a non-zero value to signify that an error has occurred.

If file is not a NULL pointer, display a success message and close the file. Then quit the program by returning 0 to show that the program terminated without errors.



Creating Files for Writing Only

To create a text file for writing only, pass "w" into fopen as the second argument.

This example follows along the same lines as the previous:

#include <stdio.h>

int main() {
  FILE *file; /* declare a FILE pointer */

  file = fopen("data/writing.txt", "w"); 
  /* create a text file for writing */

  if(file==NULL) {
    printf("Error: can't create file.\n");
    /* fclose(file); DON'T PASS A NULL POINTER TO fclose !! */
    return 1;
  }
  else {
    printf("File created. Now closing it...\n");
    fclose(file);
    return 0;
  }
}

Now, if I went into my data folder, I could see a text file called "writing" was created. However, if my data folder didn't exist, an error would occur.



Warning

Creating a file that already exists wipes all the data from that file!



Other Options When Opening Files

There are 4 other options I'd like to mention:

"a" lets you open a text file for appending - i.e. add data to the end of the current text.

"r+" will open a text file to read from or write to.

"w+" will create a text file to read from or write to.

"a+" will either create or open a text file for appending.

Add a "b" to the end if you want to use binary files instead of text files, like this:

"rb", "wb", "ab", "r+b", "w+b", "a+b".



Using fgetc To Read Characters

First, we will look at a function that allows us to read one character at a time.

fgetc requires one argument - a stream. This could either be your FILE pointer OR stdin. Writing fgetc(stdin) is the equivalent of writing getc(). We're going to be passing a FILE pointer to it.

fgetc returns the int that denotes a character from the file. For example, if the first character in the file was "A", fgetc would return 65.

After returning an int, the FILE pointer is moved to point to the next character. Should the pointer be moved beyond the last character, fgetc returns EOF - the END OF FILE constant.

We usually use EOF to determine when we've finished reading from a file.

For the next example, I created a text file called numbers.txt and placed it in the same directory as my C program. Here are its contents:

one
two
three

four
five

Here's a demonstration the use of fgetc:

#include <stdio.h>

int main() {
  char c;     /* declare a char variable */
  FILE *file; /* declare a FILE pointer  */

  file = fopen("numbers.txt", "r"); 
  /* open a text file for reading */

  if(file==NULL) {
    printf("Error: can't open file.\n");
    /* fclose(file); DON'T PASS A NULL POINTER TO fclose !! */
    return 1;
  }
  else {
    printf("File opened successfully. Contents:\n\n");
    
    while(1) {     /* keep looping... */
      c = fgetc(file);
      if(c!=EOF) {
        printf("%c", c);  
        /* print the file one character at a time */
      }
      else {
        break;     /* ...break when EOF is reached */
      }
    }

    printf("\n\nNow closing file...\n");
    fclose(file);
    return 0;
  }
}

The output is as expected:

File opened successfully. Contents:

one
two
three

four
five

Now closing file...

If you get an error, check that your text file is in the right place!

Most of the program was covered above, but the while loop iterates through the contents of the file until the end of the file is reached, reading and printing out one character at a time. Notice how the line breaks in my file causes printf to print a line break - they have the ASCII code of 10.



Prev: Unions
Next: feof, fgets and fread

www.iota-six.co.uk Copyright © 2001-2003
Unauthorized copying not permitted

Designed and Developed Using Macromedia Studio MX