第19章 open / dprintf 関数

 fprintf は便利っちゃ便利ですが物足りない部分もあります。

 なぜならファイル記述子( file descriptor )の方が便利なことが多いからです。

 fprintf はあくまでもファイルストリームの指定なので、ファイル記述子をそのまま使うなら dprintf が良いです。

#include <stdio.h>
int dprintf(int fd, const char *format, ...);

 この関数は第一引数にファイル記述子、後はフォーマット文字列、入力変数を指定します。

 printf にファイル記述子がついてるぐらいのもんです。

 後はファイル記述子は exec コマンドを使って取得するより open 関数を使ったほうが良いです。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

 open 関数には flags と mode という引数がありますね。

 flags は一般的に設定に使えるフラグパラメーターです。

 mode はファイルアクセス権限の設定に使えるフラグです。

 以下はヘッダーファイルから得られる mode の一覧です。

表19.1 mode

定数8進数値権限

S_ISUID

04000

ユーザーID設定

S_ISGID

02000

グループID設定

S_ISVTX

01000

スティッキー

S_IRUSR

0400

ユーザー読み込み

S_IWUSR

0200

ユーザー書き込み

S_IXUSR

0100

ユーザー実行

S_IRGRP

040

グループ読み込み

S_IWGRP

020

グループ書き込み

S_IXGRP

010

グループ実行

S_IROTH

04

その他の(グループ以外の全ユーザの)読み込み

S_IWOTH

02

その他の(グループ以外の全ユーザの)書き込み

S_IXOTH

01

その他の(グループ以外の全ユーザの)実行


 ここらへんは Unix 系の教科書、参考書の権限設定を見ておくと参考になるかもしれませんね。

 それとファイル記述子が開いたままだと、支障が出るので、閉じるには close 関数を使います。

#include <unistd.h>
int close(int fd);

 dprintf を使いこなすための関数は大体こんなもんですかね。

 では実装例でも見てみましょう。

main.c. 

  1 #include <stdio.h>
  2 #include <fcntl.h>
  3 #include <stdlib.h>
  4 #include <unistd.h>
  5
  6 int main(int argc, char **argv)
  7 {
  8   int fd;
  9
 10   if(argc != 2) {
 11     fprintf(stderr,"ファイル名を指定してください\n");
 12     exit(1);
 13   }
 14   fd = open(argv[1],O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
 15   if(fd < 0) {
 16     fprintf(stderr,"ファイル記述子を開けませんでした\n");
 17     exit(1);
 18   }
 19   dprintf(fd,"HELLO %s!\n",argv[1]);
 20   close(fd);
 21   return 0;
 22 }

 このコードでは open 関数をフルに使ってるん、そこが理解するときにネックになると思いますが、まずは見ないようにして動かしてみましょう。

$ gcc main.c
$ ./a.out abc.txt
$ cat abc.txt
HELLO abc.txt!

 このビルドしたプログラムのやっていることをリストにしますね。

  1. コマンドの第一引数にファイル名を指定する
  2. open 関数でファイルを新たに作成するか、既に指定したファイル名と同じファイルが存在するなら上書きし、ファイル記述子 fd を開く
  3. dprintf で HELLO ファイル名! という文字列を開いたファイル記述子 fd に書き込む
  4. ファイル記述子 fd を閉じる

 では解説してきますね。

 14   fd = open(argv[1],O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
 15   if(fd < 0) {
 16     fprintf(stderr,"ファイル記述子を開けませんでした\n");
 17     exit(1);
 18   }

 open 関数は第一引数がファイル名、第二引数が flags です。新規ファイル作成(または上書き)、読み書き両用、既存のデータがある場合はサイズ 0 に切り捨て(truncation)します。

 最後の fd 変数のチェックですが、ファイル記述子は取得に成功すると 0 以上の整数値、失敗すると -1 が返ってくるので、失敗した場合は即プログラムを終了します。

 19   dprintf(fd,"HELLO %s!\n",argv[1]);
 20   close(fd);

 dprintf の第一引数はファイル記述子、第二引数はフォーマット文字列、第三引数以降は変数リストです。

 「HELLO ファイル名!」というようにファイル記述子に出力します。

 後はファイル記述子を閉じてプログラムを終了します。

 最後にファイルの中身の確認は cat コマンドを使います。

$ cat abc.txt
HELLO abc.txt!

 このようにファイル名の情報が abc.txt に更新されてます。

Copyright 2018-2019, by Masaki Komatsu