標準入出力ライブラリでのファイル操作
標準入出力ライブラリを使用するとファイル操作がしやすく,バッファリングなども効くので便利である.
ここでは,標準入出力ライブラリを使用したファイル操作について書く.先のシステムコールを使用したファイル操作では以下のような不満があるかもしれない.
- バッファリングがない
- 書式付き出力などの機能がない
標準入出力でもシステムコールと同様,openしてreadやwriteをおこないcloseするという流れで処理する.ただし,システムコールにおけるファイルディスクリプタに相当するものは,ストリームというものに置き換わる.具体的には,openするとFileという構造体へのポインタが返って来るのでそれにたいしていろいろする.また,標準ファイルディスクリプタに対応するストリームはプログラム実行時に時動的にオープンされる.だからいきなり(openせずに)printfとかできたりする.標準ファイルディスクリプタとそれらに対応するストリームを以下に示す.
これらのストリームはstdio.hで定義されている.以下/usr/include/stdio.hから引用.
| ファイルディスクリプタ | ストリーム名 | |
|---|---|---|
| 標準入力 | 0 | stdin |
| 標準出力 | 1 | stdout |
| 標準エラー出力 | 2 | stderr |
/* Standard streams. */ extern FILE *stdin; /* Standard input stream. */ extern FILE *stdout; /* Standard output stream. */ extern FILE *stderr; /* Standard error output stream. */
システムコール編では関数の仕様を書いたけど,それって全部manに書いてあるので(というかmanを見ながら書いた)私個人にとっても意味がない.ので,今回から試用してみる(ほんとはフリーのソースとかを読んだりしたらカッチョイイんだけど,私には無理.でもいつかは....).
どうでもいいけど,なんだかとてつもなく恥ずかしいコードのような気がする(汗).
#include <stdlib.h>
#include <stdio.h>
int finalize();
int init_name();
int init_value();
char *name;
int *value;
FILE *file;
size_t result;
int main()
{
init_name();
/* nameにaとbを代入して出力 */
*name='a';
*(name+1)='b';
/* 標準出力に書式付き出力 */
fprintf(stdout,"%c\n",*name);
fprintf(stdout,"%c\n",*(name+1));
init_value();
/* valueに1と1000を代入して出力 */
*value=1;
*(value+1)=1000;
fprintf(stdout,"%d\n",*value);
fprintf(stdout,"%d\n",*(value+1));
/* hogeファイルへのストリームを書き込みモードでオープン */
file=fopen("hoge","w");
if(file==NULL){
/* 標準エラー出力に出力 */
fprintf(stderr,"File open failed (write only mode)");
finalize();
exit(-1);
}
/* ストリームへのポインタfileへnameにあるサイズcharのデータを二つ書き込む */
if(fwrite(name,sizeof(char),2,file)<0){
fprintf(stderr,"File write failed");
finalize();
exit(-1);
}
fprintf(stdout,"File write successed(name)\n");
/* ストリームへのポインタfileへvalueにあるサイズintのデータを二つ書き込む */
if(fwrite(value,sizeof(int),2,file)<0){
fprintf(stderr,"File write failed");
finalize();
exit(-1);
}
fprintf(stdout,"File write successed(value)\n");
/* 一旦忘れ去る */
finalize();
/* hogeファイルへのストリームを読み込みモードでオープン */
file=fopen("hoge","r");
if(file==NULL){
fprintf(stderr,"File open failed (read only mode)");
finalize();
exit(-1);
}
/* ストリームfileからサイズcharのデータを2つ読み込む */
if(fread(name,sizeof(char),2,file)<0){
fprintf(stderr,"Read char datas form file failed");
finalize();
exit(-1);
}
fprintf(stdout,"Readed %c\n",*name);
fprintf(stdout,"Readed %c\n",*(name+1));
/* ストリームfileからサイズintのデータを2つ読み込む */
if(fread(value,sizeof(int),2,file)<0){
fprintf(stderr,"Read int datas from file failed");
finalize();
exit(-1);
}
fprintf(stdout,"Readed %d\n",*value);
fprintf(stdout,"Readed %d\n",*(value+1));
finalize();
exit(0);
}
int finalize()
{
fprintf(stdout,"Free name....");
free(name);
fprintf(stdout,"Done\n");
fprintf(stdout,"Free value....");
/* ストリームstdoutをフラッシュする */
fflush(stdout);
free(value);
fprintf(stdout,"Done\n");
/* ストリームfileを閉じる */
fprintf(stdout,"Close file....");
if(fclose(file)!=0){
fprintf(stderr,"File close failed");
exit(-1);
}
fprintf(stdout,"Done\n");
return 1;
}
int init_name(){
/* nameにchar二個分のメモリを割り当てる */
name=malloc(2*sizeof(char));
if(name==NULL){
fprintf(stderr,"Malloc for name failed");
finalize();
exit(-1);
}
return 1;
}
int init_value(){
/* valueにint二個分のメモリを割り当てる */
value=malloc(2*sizeof(int));
if(value==NULL){
fprintf(stderr,"Malloc for value failed");
finalize();
exit(-1);
}
return 1;
}
こいつをコンパイルして実行すると,以下が出力される.
a b 1 1000 File write successed(name) File write successed(value) Free name....Done Free value....Done Close file....Done Readed a Readed b Readed 1 Readed 1000 Free name....Done Free value....セグメンテーション違反ですうん,ファイルの入出力はうまくできているようだ.が,二度目のfree(value)に失敗する.なんでだろー.
どうでもいいけど,なんだかとてつもなく恥ずかしいコードのような気がする(汗).

