fopenとfgetcとfputcとfcloseを使う

前回はシステムコールを使ってファイル読み出しをしたので、
今回はライブラリ関数を使ってファイル読み出ししてみます。

man 3でそれぞれ型の確認。

FOPEN(3)         Linux Programmer's Manual        FOPEN(3)

名前
       fopen, fdopen, freopen - ストリームを開く関数

書式
       #include <stdio.h>

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

       FILE *fdopen(int fd, const char *mode);

       FILE *freopen(const char *path, const char *mode, FILE *stream);


FGETC(3)         Linux Programmer's Manual        FGETC(3)

名前
       fgetc,  fgets, getc, getchar, ungetc - 文字と文字列の入力

書式
       #include <stdio.h>

       int fgetc(FILE *stream);

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

       int getc(FILE *stream);

       int getchar(void);

       int ungetc(int c, FILE *stream);

PUTS(3)          Linux Programmer's Manual         PUTS(3)

名前
       fputc,  fputs, putc, putchar, puts - 文字と文字列の出力

書式
       #include <stdio.h>

       int fputc(int c, FILE *stream);

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

       int putc(int c, FILE *stream);

       int putchar(int c);

       int puts(const char *s);

FCLOSE(3)        Linux Programmer's Manual       FCLOSE(3)

名前
       fclose - ストリームを閉じる

書式
       #include <stdio.h>

       int fclose(FILE *stream);

ではプログラムです。バッファがいらない分、すっきりしています。

takk@deb9:~/tmp$ cat -n fgetcfputc.c
     1	#include <stdio.h>
     2	
     3	int main()
     4	{
     5		int c;
     6		FILE *fp;
     7		fp = fopen("test.dat","r");
     8		while((c=fgetc(fp)) != -1){
     9			fputc(c,stdout);
    10		}
    11		fclose(fp);
    12	
    13		return 0;
    14	}
takk@deb9:~/tmp$ 

実行してみます。

takk@deb9:~/tmp$ gcc -o b.out fgetcfputc.c
takk@deb9:~/tmp$ ./b.out
1	2	3	4	5
6	7	8	9	10
11	12	13	14	15
16	17	18	19	20
21	22	23	24	25
26	27	28	29	30
31	32	33	34	35
36	37	38	39	40
41	42	43	44	45
46	47	48	49	50
51	52	53	54	55
56	57	58	59	60
61	62	63	64	65
66	67	68	69	70
71	72	73	74	75
76	77	78	79	80
81	82	83	84	85
86	87	88	89	90
91	92	93	94	95
96	97	98	99	100
takk@deb9:~/tmp$ 

問題なさそうです。
前回作ったシステムコールを使ったファイル読み出しの実行ファイル(a.out)と比較してみます。サイズ比較。

takk@deb9:~/tmp$ wc -c a.out b.out
 8784 a.out
 8832 b.out
17616 合計
takk@deb9:~/tmp$ 

ちょっとだけb.outの方が大きいです。ライブラリを使用するのでその分大きくなるのでしょうか。

処理時間もそれぞれ確認。余計な表示がでないように/dev/nullに読み出した値を捨てます。

takk@deb9:~/tmp$ time ./a.out >/dev/null

real	0m0.004s
user	0m0.000s
sys	0m0.000s
takk@deb9:~/tmp$ time ./b.out >/dev/null

real	0m0.004s
user	0m0.000s
sys	0m0.000s
takk@deb9:~/tmp$ 

test.datのファイルサイズが小さいから、ほとんど差が分かりません。

test.datを一旦削除して、1Gのtest.datを生成します。

takk@deb9:~/tmp$ rm test.dat
takk@deb9:~/tmp$ truncate -s1G test.dat
takk@deb9:~/tmp$ ls -lh test.dat
-rw-r--r-- 1 takk takk 1.0G  4月 11 20:40 test.dat
takk@deb9:~/tmp$ 

さて比較します。
まずはシステムコール版。

takk@deb9:~/tmp$ time ./a.out >/dev/null

real	0m8.130s
user	0m0.356s
sys	0m2.292s
takk@deb9:~/tmp$ 

1Gともなると結構かかるものですね。8秒かかりました。
次はライブラリ版。

takk@deb9:~/tmp$ time ./b.out >/dev/null

real	0m36.147s
user	0m11.792s
sys	0m0.188s
takk@deb9:~/tmp$ 

システムコールと比べて、4倍以上時間がかかりました。
連続したデータなら直接システムコールを使った方が早いということでしょうか。

コメント

タイトルとURLをコピーしました