Skip to content

Standard I/O

  • The standard I/O functions are implemented “on top of” (using) the Unix I/O functions.
  • When a file is opened, a file descriptor is returned, and that descriptor is then used for all subsequent I/O operations.
  • When we open a stream, the standard I/O function fopenreturns a pointer to a FILE object which usually contains:
    • file descriptor: for actual I/O
    • A pointer to a buffer for the stream
    • Buffer size
  • An example:
/*
Every ANSI C program begins with
three open streams, stdin, stdout, and stderr, which correspond to standard
input, standard output, and standard error, respectively:
*/
#include <stdio.h>
extern FILE *stdin; /* Standard input (descriptor 0) */
extern FILE *stdout; /* Standard output (descriptor 1) */
extern FILE *stderr; /* Standard error (descriptor 2) */
  • A stream of type FILE is an abstraction for a file descriptor and a stream buffer.

  • The purpose of the stream buffer is to minimize the number of expensive Linux I/O system calls.

  • Standard I/O support 2 kinds of files: text and binary

File operations

Opening and closing a stream

#include <stdio.h>
FILE *fopen(const char *restrict pathname, const char *restrict type);
FILE *freopen(const char *restrict pathname, const char *restrict type, FILE *restrict fp);
FILE *fdopen(int fd, const char *type);
int fclose(FILE *stream);
  • Example: fopen opens a specified file
#include <stdio.h>
#include <stdlib.h>
#define FILE_NAME "example.txt"
int main(void)
{
FILE *fp = fopen(FILE_NAME, "r");
if (fp == NULL){
printf("Can't open %s\n", FILE_NAME);
exit(EXIT_FAILURE);
}
//Do something
fclose(fp);
return 0;
}
  • Example: freopen
#include <stdio.h>
int main() {
FILE *fp;
// Open a file for writing
fp = fopen("output.txt", "w");
if (fp == NULL) {
perror("Error opening file");
return 1;
}
// Redirect stdout to output.txt
freopen("output.txt", "w", stdout);
// Now stdout is redirected, so any printf statements will go to output.txt
printf("This is redirected to output.txt\n");
// Close the file
fclose(fp);
// Restore stdout to the original stream (typically the console)
freopen("/dev/tty", "w", stdout); // On Unix-like systems
// OR
// freopen("CONOUT$", "w", stdout); // On Windows
// Now stdout is back to the console
printf("This is back to the console\n");
return 0;
}

Reading and writing a stream

#include <stdio.h>
/*
Character-at-a-time I/O: buffering is handled automatically
*/
int getc(FILE *fp);
int fgetc(FILE *fp);
int getchar(void);
int ungetc(int c, FILE *stream);
int putc(int c, FILE *fp);
int fputc(int c, FILE *fp);
int putchar(int c); // ~ putc(c, stdout);
/* Line-at-a-time I/O: Each line is terminated with a newline character, and we have to
specify the maximum line length that we can handle when we call fgets */
char *fgets(char *restrict buf, int n, FILE *restrict fp);
char *gets(char *buf );
int fputs(const char *restrict str, FILE *restrict fp);
int puts(const char *str);
// All three return: next character if OK, EOF on end of file or error
  • Example:
#include <stdio.h>
int main(void)
{
int c;
while ((c = getc(stdin)) != EOF)
if (putc(c,stdout) == EOF)
perror("output error");
if (ferror(stdin))
perror("input error");
return 0;
}

Temporary file

FILE *tmpfile(void);
char *tmpnam(char *s);

Buffering

  • The goal of the buffering provided by the standard I/O library is to use the minimum number of read and write calls.
  • Data written to a stream is actually stored in a buffer area in memory; when it’s full (or the stream is closed), the buffer is “flushed” (written to the actual output device).
  • Input streams can be buffered in a similar way: the buffer contains data from the input device; input is read from this buffer instead of the device itself.
fflush(fp); /* flushes buffer for fp */
fflush(NULL); /* flushes all buffers */
  • Example: fflush
#include <stdio.h>
int main()
{
FILE *fp;
char str[] = "This is a test string.";
fp = fopen("test.txt", "w");
if (fp == NULL){
perror("Error opening file.");
return -1;
}
fputs(str, fp);
if (fflush(fp) != 0){
perror("Error flushing file");
return -1;
}
fclose(fp);
//We don't use fflush, buffer is automatically flushed when its fulled or the file is closed
}