Binary and Text IO in C

"Every program has at least one bug and can be shortened by at least one instruction -- from which, by induction, it is evident that every program can be reduced to one instruction that does not work." -- Anonymous

Basic Output

To use the I/O facilities of C, you need to include stdio.h.

The simplest facilities for unformatted output in C are putchar and puts:

int putchar( int c );
int puts( const char *string );
Both mechanisms output the character or string at the current cursor position.

Default open stream pointers:

They are part of the standard I/O library in stdio.h so you don't need to declare them:

The definition of a FILE used by Microsoft's compiler:

struct _iobuf {
        char *_ptr;
        int   _cnt;
        char *_base;
        int   _flag;
        int   _file;
        int   _charbuf;
        int   _bufsiz;
        char *_tmpfname;
        };
typedef struct _iobuf FILE;

_CRTIMP extern FILE _iob[];

#define stdin  (&_iob[0])
#define stdout (&_iob[1])
#define stderr (&_iob[2])
You will probably never have to deal with the internal structure of a FILE and can just assume that the standard I/O devices are declared like this:
FILE *stdin;
FILE *stdout;
FILE *stderr;

Functions/macros for unformatted output to stdout or a specified FILE pointer:

  // These two output to stdout
int putchar( int c );  // macro
int puts( const char *string ); 

  // You need to specify the stream with these
int putc( int c, FILE *stream ); // macro
int fputc( int c, FILE *stream );
int fputs( const char *string, FILE *stream );
Notes:

Redirecting stdout and stderr

Suppose we had a function that did this:

void ShowOutErr(void)
{
  fputs("This is going to stdout\n", stdout);
  fputs("This is going to stderr\n", stderr);
}
By default, running this program would produce this output on the console (display):
This is going to stdout
This is going to stderr
We can redirect these messages to a file by using the output redirection operator at the console. (Assume the function above compiles to a program called myprog.exe.)
myprog > out.txt
When we run the program, we see this printed to the screen:
This is going to stderr
What happened to the line "This is going to stdout"? Well, it was redirected to a file named out.txt. If we look at the contents of this file we see:
This is going to stdout
To redirect stderr, we need to do this:
myprog 2> err.txt
This produces the output:
This is going to stdout
The redirection also created a file named err.txt that contains the other line of text.

To redirect both, we do this:

myprog > out.txt 2> err.txt
which produces no output on the screen. Both lines of text have been redirected to their respective files (out.txt and err.txt).

If we want both stdout and stderr redirected to the same file (both.txt), we would do this:

myprog > both.txt 2>&1
Notes:

Basic Input

The simplest facilities for unformatted input in C are getchar and gets:
int getchar( void );
char *gets( char *buffer );
Notes: Functions/macros for unformatted input from stdin or a specified FILE pointer:
  // These two input from stdin
int getchar( void ); // macro
char *gets( char *buffer );

  // You need to specify the stream with these
int getc( FILE *stream ); // macro
int fgetc( FILE *stream );
char *fgets( char *string, int n, FILE *stream );
Notes:

File Input/Output

Text Files

Text streams have certain attributes that may vary among different systems:

Binary files have no restrictions or limitations. It is up to the programmer to decide when to interpret a file as a text file, and when to interpret it as a binary file.

Like most languages, reading from a file and writing to a file follow these steps:

  1. Open the file (fopen)
  2. Read/Write the file (fgetc, fgets, fputc, fputs, etc.)
  3. Close the file (fclose)
These two functions are required in all cases:
FILE *fopen( const char *filename, const char *mode );
int fclose( FILE *stream );
Notes: This text below has been saved in 3 different formats here: Windows, Linux, and Macintosh. You'll have to download the files and view them in a hex editor to see the differences. (Most web browsers can handle all types of EOL characters so they'll display it correctly.)

When in the Course of human events, it becomes necessary for one people to dissolve the political bands which have connected them with another, and to assume among the powers of the earth, the separate and equal station to which the Laws of Nature and of Nature's God entitle them, a decent respect to the opinions of mankind requires that they should declare the causes which impel them to the separation.

Example

This example displays the contents of a given text file. (We're assuming we can interpret it as text.)

#define MAX_LINE 1024

void DisplayTextFile(void)
{
  char filename[FILENAME_MAX];
  FILE *infile;

    // Prompt the user for a filename
  puts("Enter the filename to display: ");

    // Get the user's input (unsafe function call!)
  gets(filename);

    // Open the file for read in text/translate mode
  infile = fopen(filename, "r");

    // If successful, read each line and display it
  if (infile)
  {
    char buffer[MAX_LINE];

      // Until we reach the end
    while (!feof(infile))
    {
        // Get a line and display it (safe function call)
      if (fgets(buffer, MAX_LINE, infile))
        fputs(buffer, stdout);
    }

      // Close the file (very important!)
    fclose(infile);
  }
  else
    perror(filename);  // couldn't open the file
}
If the fopen fails, we call perror to display the reason. If we try to open a non-existent file named foo.txt, we'll see this:
foo.txt: No such file or directory
Notes: The same program above but reading in binary mode instead of text mode.


Binary Input/Output

For binary I/O, use fread and fwrite:
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
Info: Note that the return value is not the number of bytes written, but the number of elements written. The number of actual bytes written will be the number of elements written multiplied by the size of each element. Examples using fread and fwrite.

Contents of a file after writing 5 integers to the file (from previous example):

Big endian
000000  12 34 56 78 12 34 56 79 12 34 56 7A 12 34 56 7B  4Vx4Vy4Vz4V{
000010  12 34 56 7C                                      4V|
Little endian
000000  78 56 34 12 79 56 34 12 7A 56 34 12 7B 56 34 12  xV4yV4zV4{V4
000010  7C 56 34 12                                      |V4
Quick endian refresher


Other Input/Output Functions

int ungetc( int c, FILE *stream );
int fflush( FILE *stream );
long ftell( FILE *stream );
int fseek( FILE *stream, long offset, int origin );
int feof( FILE *stream );
int rename( const char *oldname, const char *newname );
int remove( const char *path );
char *tmpnam( char *string );
Description: Notes: File I/O Documentation from MSDN.