Sequential IO with stdin & stdout#

Opening a file#

FILE *fopen(char *path, char* mode);
int fclose(FILE *stream);

When we open a file, then we get a stream or a FILE *. We use the stream with write & read functions.

We should close the file after we are finished processing the file. Closing guarantees that the data we write to the file are indeed written to the file. If we don’t close the file, then the OS will close it after the program ends.

Opening a file is not the same as having the sole access to the file. On Linux on MacOS, other programs can still read & write; on Windows, other programs can read but not write. This is the default behavior and can be changed.

Writing & reading strings#

int fputs(char *s, FILE *stream);
char *fgets(char *s, int size_of_s, FILE *stream);

// With formatting
int fprintf(FILE *stream, char *format);
int fscanf(FILE *stream, char *format);

// stdout
int puts(char *s);
  • f stands for file.

  • puts adds a newline. If you don’t want it, use printf or fputs.

  • fgets requires size and stdout explicitly.

  • the sister of puts, char *gets(char *s) used to exist, but is deprecated now due to security. It is impossible to know in advance how many characters we will read, so it could lead to buffer overflow.

🤔 Question to ponder

Why does fgets require size but fputs does not?

Opening modes#

mode

meaning

mode+

meaning

r

read

r+

read + write

w

write

w+

write + read

a

append

a+

append + read

⚡ Live programming

Example below

#include <stdio.h>

#define LINE_MAX 80

void write_to_a_file() {
  FILE *fp = fopen("file.txt", "w");
  // open file with only write permissions

  fputs("First string", fp);
  fputs("Second string", fp);
  fputs("\nNew line", fp);

  fclose(fp);
}

void read_from_a_file() {
  FILE *fp = fopen("file.txt", "r");
  // only read permissions

  char line[LINE_MAX];
  fgets(line, LINE_MAX, fp);
  puts(line);

  fgets(line, LINE_MAX, fp);
  puts(line);
}

int main() {
  write_to_a_file();
  read_from_a_file();
}
First stringSecond string

New line

Activity 59 (Processing temperature data)

temperatures.txt contains several temperature measurements:

20
21
18
18
19
20
22

Write a single program that do the following actions. For each point, open and close the file separately.

  1. Reads five lines from temperatures.txt file and prints them to the console.

  2. Creates a new file temperatures-today.txt and writes three temperature measurements.

  3. Appends a new measurement to temperatures-today.txt.

  4. Creates an empty file measurements-done.txt

  5. Reads five lines from temperatures.txt and writes the temperatures which are greater than 19 to temperatures-filtered-some.txt. Use a for loop that reads five times.

    For conversion between string and integer you can use

  • fgets + strtol

  • or fscanf + fprintf for integer conversion.

  1. Same to the last specification, but:

    1. read all lines using while(line = fgets(...)).

    2. output to temperatures-filtered-all.txt.

    What does fgets return if we arrive at the end of the file? Refer to the documentation.

Appendix#

Character-oriented functions#

int fputc(int c, FILE *stream);
int fgetc(FILE *stream);

// stdout & stdin
int putchar(int c);
int getchar(void);

String-oriented functions use character-oriented functions. This is useful for implementing input-output (IO) for special hardware. Let’s assume you are programming a microcontroller and want to use an LCD to display data. You can implement putchar to write a character to the LCD’s display memory and maybe to move the cursor afterwards, e.g.,:

int putchar(int c) {
  lcd_write(c);  
  lcd_move_cursor();
  return c;
}

Then you can use puts or printf to display whole strings.

🥡 Takeaway

String-oriented functions are built on top of the character-oriented functions.

If you provide, i.e., implement a character-oriented function like putc, you can determine what string functions do.

putc && getc#

int putc(int c, FILE *stream);
int getc(FILE *stream);

These are input-output-wise functionally equivalent to fputc and fgetc. I don’t mention these functions, because these functions are in the standard for performance. They are allowed to be implemented as macros.

More info: