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);
fstands for file.putsadds a newline. If you don’t want it, useprintforfputs.fgetsrequiressizeandstdoutexplicitly.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.
Why does fgets require size but fputs does not?
Opening modes#
mode |
meaning |
mode+ |
meaning |
|---|---|---|---|
|
read |
|
read + write |
|
write |
|
write + read |
|
append |
|
append + read |
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.
Reads five lines from
temperatures.txtfile and prints them to the console.Creates a new file
temperatures-today.txtand writes three temperature measurements.Appends a new measurement to
temperatures-today.txt.Creates an empty file
measurements-done.txtReads five lines from
temperatures.txtand writes the temperatures which are greater than 19 totemperatures-filtered-some.txt. Use a for loop that reads five times.For conversion between string and integer you can use
fgets+strtolor
fscanf+fprintffor integer conversion.
Same to the last specification, but:
read all lines using
while(line = fgets(...)).output to
temperatures-filtered-all.txt.
What does
fgetsreturn 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.
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: