Library I/O Modes in Unix/Linux

The Mode parameter in fopen() may be specified as

“r”, “w”, “a” :  for READ, WRITE, APPEND.

Each of the mode string may include a + sign, which means for both READ, WRITE, and in the cases of WRITE or APPEND, create the file if it does not exist.

“r+” :   for R/W, without truncating the file.

“w+”:   for R/W, but truncate the file first; create if file does not exist.

“a+” :  for R/W by append; create if file does not exist.

1. Char Mode I/O

int fgetc(FILE *fp):          // get a char from fp, cast to int.
int ungetc(int c, FILE *fp);  // push a previously char got by fgetc() back to stream
int fputc(int c, FILE *fp);   // put a char to fp


Note that fgetc() returns an integer, not a char. This is because it must return EOF on end of file. The EOF symbol is normally an integer -1, which distinguishes it from any char from the FILE stream.

For fp = stdin or stdout, c = getchar(); putchar(c); may be used instead. For run time efficiency, getchar() and putchar() are often not the shortened versions of getc() and putc(). Instead, they may be implemented as macros in order to avoid an extra function call.

Example 9.3: Char Mode I/O

(1). /* file copy using getc(), putc() */

#include <stdio.h>

FILE *fp,*gp;

int main()

{

int c; /* for testing EOF */

fp=fopen(“source”, “r”);

gp=fopen(“target”, “w”);

while ( (c=getc(fp)) != EOF )

putc(c,gp);

fclose(fp); fclose(gp);

}

Exercise 9.2: Write a C program which converts letters in a text file from lowercase to uppercase.

Exercise 9.3: Write a C program which counts the number of lines in a text file.

Exercise 9.4: Write a C program which counts the number of words in a text file. Words are sequences of chars separated by white spaces.

Exercise 9.5: Linux’s man pages are compressed gz files. Use gunzip to uncompress a man page file. The uncompressed man page file is a text file but it is almost unreadable because it contains many special chars and char sequences for the man program to use. Assume ls.1 is the uncompressed man page of ls.1.gz. Analyze the uncompressed ls.1 file to find out what are the special chars. Then write a C program which eliminates all the special chars, making it a pure text file.

2. Line mode I/O

char *fgets(char *buf, int size, FILE *fp):         read a line (with a \n at end) of at most size chars from fp to buf .

int fputs(char *buf, FILE *fp):                          write a line from buf to fp.

Example 9.4: Line Mode I/O

#include <stdio.h>

FILE *fp,*gp;

char buf[256]; char *s=”this is a string”;

int main()

{

fp = fopen(“src”, “r”);

gp = fopen(“dest”, “w”);

fgets(buf, 256, fp); // read a line of up to 255 chars to buf

fputs(buf, gp);  // write line to destination file

}

When fp is stdin or stdout, the following functions may also be used but they are not shortened versions of fgets() and fputs().

gets(char *buf);      // input line from stdin but without checking length

puts(char *buf);      // write line to stdout

3. Formatted I/O

These are perhaps the most commonly used I/O functions.

Foratted Inputs: (FMT¼format string )

scanf(char *FMT, &items);  // from stdin
fscanf(fp, char *FMT, &items);  // from file stream

Formatted Outputs:

printf(char *FMT, items);  // to stdout
fprintf(fp, char *FMT, items);  // to file stream

4. In-memory Conversion Functions

sscanf(buf, FMT, &items);     // input from buf[ ] in memory

sprintf(buf,FMT, items);      // print to buf[ ] in memroy

Note that sscanf() and sprintf() are not I/O functions but in-memory data conversion functions. For example, atoi() is a standard library function, which converts an string of ASCII digits to integer, but most Unix/Linux system do not have an itoa() function because the conversion can be done by sprintf (), so it is not needed.

5. Other Library I/O Functions

6. Restriction on Mixed fread-fwrite

When a file stream is for both RIW, there are restrictions on the use of mixed fread() and fwrite() calls. The specification requires at least one fseek() or ftell() between every pair of fread() and fwrite().

Example 9.5: Mixed fread-fwrite: This program yields different results when run under HP-UX and Linux.

#include <stdio.h>
FILE fp; char buf[1024];
int main()
{

fp = fopen(“file”, “r+”);  // for both R/W
fread(buf, 1, 20, fp);  // read 20 bytes
fwrite(buf,1, 20, fp); // write to the same file

}

Linux gives the right result, which modifies the bytes from 20 to 39. HP-UX appends 40 bytes to the end of the original file. The difference stems from the non-uniform treatment of R/W pointers in the two systems. Recall that fread()/fwrite() issue read()/write() system calls to fill/flush the internal buffer. While read()/write() use the R/W pointer in the file’s OFTE, fread()/fwrite() use the local buffer’s R/W pointer in the FILE structure. Without a fseek() to synchronize these two pointers, the results depend on how are they used in the implementations. In order to avoid any inconsistencies, follow the suggestions of the man pages. For the Example 9.5 program, the results become identical (and correct) if we insert a line

fseek(fp, (long)20, 0);

between the fread() and fwrite() lines.

Source: Wang K.C. (2018), Systems Programming in Unix/Linux, Springer; 1st ed. 2018 edition.

Leave a Reply

Your email address will not be published. Required fields are marked *