標準入出力(stdio)を用いたcat


stdioでの標準入出力により、catコマンド作成します。
readやwriteといったシステムコール呼び出しは関数呼び出しよりも大変遅いようです。
そのため、標準入出力ライブラリー(stdio)に記述されている一連の関数を用いることが通例のようです。
stdioでは、ストリームからreadを用いて読み込んだデータをバッファと呼ばれる一時記憶領域に保存し、そこからユーザー指定の任意のデータを抽出するような処理方式になっているようです。
stdioはプログラムとストリームの間にバッファ(緩衝)を用意し、readやwriteの機能を修飾する役目を持っていると考えます。



/* mycat.c */
#include<stdio.h> /* fopen, fgetc, fclose, putchar */
#include<stdlib.h> /*  */

int main(int argc, char *argv[])
{
        int i;

        for(i = 1; i<argc; i++){
                FILE *f;        /* FILE型へのポインタ */
                int c;

                f=fopen(argv[i], "r"); /* ファイルパスを指定して、そのファイルにつながるストリームを作り
                                          それを管理するFILE型へのポインタを返し、fへ格納する*/
                /*何らかの理由で失敗した場合は、NULLを返し、errnoに原因に対応する値を格納する。*/
             
                if(!f){
                        perror(argv[i]); /* エラー処理 */
                        exit(1);
                }

                while((c = fgetc(f)) != EOF){   /* fputcでストリームからバイト単位でデータを読み込む */
                                                /* ストリームの場合はEOF(-1)が返されるため、*/
                                                /*戻り値を格納する変数もint型である。*/
        if(putchar(c) < 0) exit(1); /* バイト単位の出力APIのputcharを用いる。*/
        }
        fclose(f);      /*fが参照するストリームを閉じる。*/
        }
        exit(0);
}


$ gcc -o mycat mycat.c

$ echo "It is sunny today." > test.txt

$ ./mycat test.txt
It is sunny today.

#ファイルパーミッションを変更して読み取り不可にする
$ sudo chmod -r test.txt 
$ ./mycat test.txt 
test.txt: Permission denied

#存在しないファイル名(hogehoge)を指定してプログラムを実行
$ ./mycat hogehoge
hogehoe: No such file or directory