Logo  

CS351 - Computer Organization

Reading and Writing To and From Files:

FILE *fopen(const char *pathname, const char *mode);

  • Opens the file located at 'pathname'. The value returned from fopen() is a "file stream", which is used by other functions, such as fgetc(), fgets() or fputs() to read/write data to that file stream. If the return value is NULL then fopen failed to open the file.

  • 'mode' is one of (see Notes below for meaning of b,e,c and t):

mode File is opened for
"r" Reading (b)
"r+" Reading and writing (b)
"w" Writing (t,c,b)
"w+" Reading and writing (t,c,b)
"a" Append (write) (c,e)
"a+" Reading and appending (c,b (when reading), e (when writing))

Notes:

b = Stream positioned at the beginning of file
e = String positioned at the end of file
c = Creates the file if it does not exist.
t = Truncates the file to zero length on open if it does exist.

Example:

// Opens the file "file.txt" for reading, stream is positioned at the start
// of the file:
FILE *fptr = fopen("file.txt", "r");

int fclose(FILE *stream);

  • Closes the file stream. A Program can usually only have about 1000 files opened. The stream is no longer valid after it is closed.

    Example:

    // Releases the stream that fptr points to back to the system:
    fclose(fptr);

Functions for reading from a FILE stream:

int fgetc(FILE *stream);

  • Reads a character from the given stream, just like getchar() reads from stdin. getchar() is actually just fgetc(stdin)

    Example:

    // Read a character from the file stream, then print it on the screen:
    while((ch = fgetc(fptr)) != EOF) putchar(ch);

char *fgets(char *str, int size, FILE *stream);

  • Reads a string of characters of at most size-1 length into the character array (i.e. a string) str from the stream. Returns NULL when EOF is reached, non-NULL otherwise. Use stdin for the file stream to read from the keyboard.

    Example:

    // Reads a line of text (up to 1023 characters) into buf from the file
    // opened above:
    char buf[1024];
    fgets(buf, 1024, fptr);

Functions for writing to a FILE stream:

int fputc(int c, FILE *stream);

  • Writes a single character (c) to the given file stream.

Example:

FILE *src = fopen("input.txt", "r");
FILE *dst = fopen("output.txt", "w");

int ch;
while ( (ch = fgetc(src)) != EOF ) {
  fputc(ch, dst);
}

fclose(src);
fclose(dst);


This example copies the file input.txt to output.txt. It will create the file output.txt if it does not exist and over-write it if it does. After the files are opened, the data from input is read one character at a time from the src stream (input.txt) and written one character at a time to the file stream dst (output.txt). Once all the data has been read from src, both files are closed and the copy is completed.

int fputs(const char *s, FILE *stream);

  • This is the opposite of fgets(), writing the string given by s to the file stream.

Example

char buf[1024];

while (fgets(buf, 1024, src) != NULL) {
  fputs(buf, dst);
}

More examples:

read-one.c

int ch;

// Open file.txt for reading and assign the FILE pointer to fp:
FILE *fp = fopen("file.txt", "r");
if (fp == NULL) {  // Check that the file could not be opened:
  perror("fopen"); // perror print the error that caused the failure.
  exit(1);
}

// Read a single character at a time from the file, then print it to the screen:
while((ch = fgetc(fp)) != EOF) {
  putchar(ch);
}

fclose(fp);

Note: that it is important to wrap the ch = fgetc(fp) inside of ()'s as:

(ch = fgetc(fp)) != EOF

is not the same as:

ch = fgetc(fp) != EOF

The latter is actually equivalent to:

ch = (fgetc(fp) != EOF)

Which would make ch either true or false (i.e. whether the character read was the End of File or not,) and not the value of the character read. Always wrap an assignment inside of ()'s when comparing the result of the assignment with a value.

read-line.c

char buf[1024];

// Open and check for error in one if statement.  Note that the assignment must
// be contained inside of ()'s:
if ( (FILE *fp = fopen("file.txt", "r")) == NULL ) {
  perror("fopen");
  exit(1);
}

// Read a whole line at a time:
while(fgets(buf, 1024, fp) != NULL) {
  printf("%s", buf);
}

fclose(fp);

more.c

Displays a file on the screen, one screen-full at a time:

#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <sys/ioctl.h>

void clear(void)
{
  // Homes the cursor ( <esc>[0H ) then clears the screen ( <esc>[2J )
  printf("\033[0H\033[2J");
}

int main(int argc, char *argv[])
{
  if (argc < 2) {
    printf("Usage: more <file>\n");
    return 0;
  }

  FILE *fp = fopen(argv[1],"r");
  if (fp == NULL) {
    printf("Unable to open %s\n", argv[1]);
    return 1;
  }

  struct winsize ws;

  // This ioctl gets the size of the terminal window:
  ioctl(STDIN_FILENO, TIOCGWINSZ, &ws);
  int width = ws.ws_col;    // Number of columns
  int height = ws.ws_row;   // Number of rows

  // These two variables determine where the next character is printed:
  int line = 0, column = 0;
  int ch;
  char buf[80];

  clear();

  // Reads only one character at a time:
  while((ch = fgetc(fp)) != EOF) {
    /**
     * If the character read is a new-line, move to the beginning of the next
     * line, Otherwise add the character unless we reach the last column in
     * which case we print a diamond indicating there is potentially more
     * characters not displayed. Any character beyond that is not printed.
     */
    if (ch == '\n') {
      putchar(ch);
      line++;
      column = 0;
    } else if (column < width-2) {
      putchar(ch);
      column++;
    } else if (column == width-1) {
      putchar('\273');
      column++;
    } else column++;

    // Stop when we get to the last line, printing a prompt and wait for input
    // to continue:
    if (line == height-1) {
      printf("More? ");
      // Get a complete line of input from the user:
      fgets(buf, 80, stdin);
      // Exit if a 'q' or 'Q' is entered:
      if (buf[0] == 'q' || buf[0] == 'Q') return 0;
      // Clear the screen and reset line/column back to the origin:
      clear();
      line = 0;
      column = 0;
    }
  }
  printf("Done> ");
  fgets(buf, 80, stdin);

  return 0;
}