第52章 低水準ファイル入出力 その3


さて、今回は低水準ファイル入出力を用いて ファイルの訂正をするプログラムを考えます。 簡単な住所録を作ってみましょう。 このプログラムには、ファイルの読み込み、データの追加、データの修正 という機能を持たせましょう。

まずは、main関数にメニューを作りましょう。 そして、必要な作業はこのメニューから関数として 呼び出すようにしましょう。

int main(void) { char mode[8]; strcpy(file_name, " "); while(1) { printf("1:読み込み 2:追加 3:修正 4:終了 ="); gets(mode); if (mode[0] == '4') break; switch(atoi(mode)) { case 1:read_file(); break; case 2:write_file(); break; case 3:edit_file(); break; default: printf("入力エラーです。\n"); break; } } printf("終了します。\n"); return 0; }

さて、これだけでは走らないので read_file(), write_file(), edit_file()関数は とりあえず作るだけ作っておいて中身は、 return文だけにしておきましょう。後は、 インクルードするファイルを書いて、とりあえず コンパイルして動かしてみて下さい。 間違ってメニュー選択で2バイト文字などを入力してしまっても 大丈夫です。int mode;としないでchar mode[8];としている点に 注意して下さい。また、scanfを使わずにgetsを使っている点も 注意して下さい。また、switch(mode)ではなく switch(atoi(mode))とした点も大事ですね。 (そんなことわかってる?)それから、これは筆者の 好みなのですが、while(1)で無限ループにして breakで脱出する方法も覚えておいて下さい。 while-do文でも同様のことができます。

次に、住所録ですから当然氏名と住所は必須です。 それぞれの大きさ(バイト数)を決めましょう。 とりあえず氏名は20バイト住所は40バイトまでとします。 文字列には、最後にヌル文字(\0)が入るので実際には name[21]とかaddress[41]などといった感じになります。 それとファイル名はファイルがオープンされていないときは 半角のスペースを入れておきましょう。 そうすればファイル名が半角スペースであれば あらためて、ファイル名の入力を促すようにできます。 それでは、read_file関数を作ってみましょう。

int read_file(void) { int cnt = 1; char name[21]; char address[41]; if (strcmp(file_name, " ") == 0) { printf("ファイル名="); gets(file_name); } hdl = _open(file_name, _O_RDONLY); if (hdl == -1) { printf("エラーです\n"); exit(-1); } while(_read(hdl, name, 20) > 0) { _read(hdl, address, 40); printf("[%2d]%s\n", cnt++, name); printf(" %s\n", address); } _close(hdl); return 0; }

これは、すでにやったことばかりなので説明は不要ですね。 この関数では、データの数が少ないうちはよいのですが 1画面で表示仕切れないときは、最初の方のデータが スクロールしてしまいゆっくりみることができません。 20行以上表示するときは、次の表示を行ってよいか ユーザーに聞くようにプログラムを改良してみて下さい。 そんなに難しくはありません。

それと_openとか_read, _closeなど低水準ファイル入出力 に関係のある関数でマイクロソフトのコンパイラ以外を お使いの人はそのままではエラーになる可能性があります。 関数の前のアンダスコアはとって下さい。また、 _O_RDONLYの一番最初のアンダスコアもとってください。

次は、write_file関数ですがこれも特に新しいことは出てきません。

int write_file(void) { char name[21]; char address[41]; char yn[4]; long fp = 0; if (strcmp(file_name, " ") == 0) { printf("ファイル名="); gets(file_name); } hdl = _open(file_name, _O_WRONLY | _O_CREAT | _O_APPEND, _S_IREAD | _S_IWRITE); while(1) { memset(name, ' ', sizeof(name)); memset(address, ' ', sizeof(address)); printf("氏名="); gets(name); if (strcmp(name, "E") == 0) break; printf("住所="); gets(address); _write(hdl, name, 20); _write(hdl, address, 40); printf("書き込み終了?(y/n)="); gets(yn); if (yn[0] == 'y' || yn[0] == 'Y') break; } _close(hdl); return 0; }

_open(file_name, _O_WRONLY | _O_CREAT | _O_APPEND, _S_IREAD | _S_IWRITE);

について少し解説しますが、追加の場合全く新規に ファイルを作る場合もあります。それで_O_CREATが入っています。 すでにファイルが存在する場合は、無視されます。 また、書き込みは追加ですから常にファイルの最後から 行わなくてはいけません。従って_O_APPENDを入れてあります。 そして、マイクロソフト(特有の問題?)のコンパイラでは さらに3番目の引数を付けて下さい。そうしないと作られたファイルの 属性が「読み込み専用」となりまずい問題が生じます。 筆者はこれで引っかかって、このプログラムを作るのに 大変な時間を費やしてしまいました。

ところで、memsetは何のために使っているの?

はい。なくてもかまいません。 自分でファイル入出力のプログラムを作ってあれこれやってみると わかると思いますが、上のプログラムでmemsetを取り払って しまうと、作られたファイルにゴミが入ってしまいます。 メモ帳でみるとわかります。それを防ぐために、まず nameやらaddressを半角スペースで埋めてしまいました。 ただそれだけのことです。

すでにお気付きのことと思いますがhdlとfile_nameは グローバル変数にしてあります。

次に、肝心のデータの編集ですが少しばかり説明が必要です。 しかし、紙面?がなくなってきたので次回に説明しましょう。 本日はここまで。


[Index][総合Index] [Previous Chapter] [Next Chapter]

Update Mar/01/1997 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。