File input and output

On a unix system, and by extension in a C program, a file is just a sequence of char values. They arrive in a stream and can be read in (or written out) by a program using tools that are already pretty familiar from our console input and output.

In fact, printf, puts, scanf, etc. all work on files, but the files are implied—every C program automatically has three files open, the standard input, output, and error message streams. You can open new streams connected to files in the filesystem with fopen, and close them when you’re done with fclose. In the mean time, you can use fprintf, fputs, fscanf, etc., the same as the familiar functions but with an explicit file parameter.

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

int main()
{
    FILE *f;

    f = fopen("output", "w");
    if (!f) {
        puts("Couldn't open output file");
        exit(EXIT_FAILURE);
    }

    fputs("hello, world", f);

    fclose(f);
}

The call to fopen takes two arguments: first, the filename, and second, a mode indicating what you want to do with that file. This example uses mode "w" for ‘writing’; in this mode, the file is created if it does not already exist, and any contents previously in it are erased, so you have a clean slate to write output to. For various reasons, opening a file can fail, and this example handles that with a conditional that will handle failure by printing a message and exiting (the exit function and the EXIT_FAILURE code are brought in from stdlib.h).

The fputs function is similar to puts, but rather than writing the message to the standard output stream, it takes a second parameter indicating which file stream to use, in this case, the one we just opened. (Also, unlike puts, fputs doesn’t implicitly add a newline, so you have to use \n if you want one.)

Input and output to streams is buffered, so the message isn’t necessarily written to the hard drive immediately. When you close or explicitly flush the buffer, the file will reconcile with the buffer. If you forget to close a file, there won’t be much harm in a program this simple, since open files are implicitly closed when the program ends anyway, but it is a good habit to get into to always have a plan to explicitly release resources you have allocated.

The following program reads in two numbers from a file and prints their sum.

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

int main()
{
    FILE *f;
    int a;
    int b;

    f = fopen("input", "r");
    if (!f) {
        puts("Can't open input file");
        exit(EXIT_FAILURE);
    }

    if (fscanf(f, "%d %d", &a, &b) != 2) {
        puts("Didn't get both numbers");
        exit(EXIT_FAILURE);
    }

    fclose(f);

    printf("%d + %d = %d\n", a, b, a + b);
}

This time, a file is opened with mode "r", for ‘reading’. The fscanf function is identical to scanf except you specify which file to scan from as the first argument. This code checks the return value to make sure that the input was valid; the scanf family of functions return how many conversions were successful, and the format "%d %d" expects two decimal numbers with whitespace between them so the return value should be 2. When you test this program, try running it with no file named input, or with invalid input in the file (you can create it with your text editor). When the file actually does exist and begin with two numbers, this program will scan them in, close the file once it’s no longer needed, and print out the sum.

If you ever need to explicitly mention one of the standard streams as a FILE * argument, they are stdin (standard input), stdout (standard output), and stderr (standard error).

The manual pages for e.g. printf, scanf, puts, or getline will mention variations that include the ones that accept file parameters.

You have attempted of activities on this page