- 作者: 塚越一雄
- 出版社/メーカー: 技術評論社
- 発売日: 2000/06
- メディア: 単行本
- 購入: 3人 クリック: 56回
- この商品を含むブログ (35件) を見る
前回はこちら
今回からファイル操作についてまとめます。
通常、C言語を使ったファイル操作と言うとstdio.hに宣言されているライブラリ関数を使用することがほとんどです。
# fopen()やfprintf(),fscanf(),fputs(),fgets()が該当します
このようなライブラリ関数には以下のような工夫がされていて使いやすくなっています。
-
- データのバッファリング(まとめて書き込むこと)を使ったりして効率がいい
- データの型変換などの機能がついている
これに対してシステムコールとして用意されている関数はより原子的な機能しか有していません。例えば
-
- n文字入力する(n=1,2,3...)
- n文字出力する(n=1,2,3...)
- 入出力位置を変更する
といった機能です。これを低水準ファイル入出力と呼びます。
# 対して前者のライブラリ関数を高水準ファイル入出力と呼びます
高水準ファイル入出力の良い点としては、上記のとおり機能が豊富である事や処理効率が高い事が挙げられますが、それ以上にC言語標準のライブラリを使用することで開発環境に依存しない開発を行えます。
逆に低水準ファイル入出力の良い点としては、OSに依存している==ライブラリよりもハードウェアに近い機能を利用出来る点です。そもそも各種ライブラリ関数はより低水準なファイル入出力を使って実装されているので、当たり前の話といえばそのとおりですが...。
私のイメージではライブラリ関数を使うことはオートマの車を運転する事に近くて、システムコールを使うことはマニュアルの車を運転する事に近いです。どちらが良いのかはその場その場で変わってきます。
今回は低水準ファイル入出力についてのみ扱います。高水準の方はC言語の入門書を読んでください。
# 私はこれ↓で勉強しました
- 作者: 内田智史,システム計画研究所
- 出版社/メーカー: オーム社
- 発売日: 2001/11/01
- メディア: 単行本
- クリック: 7回
- この商品を含むブログ (7件) を見る
使用するシステムコールの定義はこちら。
/*** ファイルを開く ***/ // #include <sys/types.h> // #include <sys/stat.h> // #include <fcntl.h> // // 第一引数 開くファイル名(絶対パスで指定) // 第二引数 アクセスフラグ // 第三引数 ファイルに設定する許可(省略可) // // 返却値 // 成功時 : 開いたファイルのファイルディスクリプタ // 失敗時 : -1 int open(const char *path, int flags); int open(const char *path, int flags, mode_t mode); /*** ファイルを閉じる ***/ // #include <unistd.h> // // 第一引数 閉じるファイルディスクリプタ // // 返却値 // 成功時 : 0 // 失敗時 : -1 int close(int fd); /*** ファイルを読む ***/ // #include <unistd.h> // // 第一引数 読み込むファイルのファイルディスクリプタ // 第二引数 読み取ったデータの格納先アドレス // 第三引数 読み取りバイト数 // // 返却値 // 1以上 読み込んだデータバイト数 // 0 ファイルの末尾に達している // -1 エラーが発生 ssize_t read(int fd, void *buf, size_t count); /*** ファイルに書き込む ***/ // #include <unistd.h> // // 第一引数 書き込むファイルのファイルディスクリプタ // 第二引数 書き込むデータの格納元アドレス // 第三引数 書き込みバイト数 // // 返却値 // 0以上 読み込んだデータバイト数 // -1 エラーが発生 ssize_t write(int fd, void *buf, size_t count);
まずはファイルを開き、データを読み取り、後始末をする部分を説明します。
/********************************************** * dataread.c * 引数で指定されたファイルを表示する **********************************************/ #include <unistd.h> #include <fcntl.h> #include <stdio.h> int main(int argc, char *argv[]) { int fd; char c ; ssize_t len; // 引数が足りなかったらエラーを表示して終了 // if ( argc < 2 ) { fprintf(stderr,"usage: %s filename\n",basename(argv[0]) ); return 1; } // ファイルを読み取り専用で開く際にエラー // if ( ((fd = open(argv[1],O_RDONLY)) == -1 ) { perror("open()"); return 2; } do { // ファイルを1文字ずつ読み込む // len = read(fd, &c, 1); if ( len < 0 ) { perror("read()"); } } while ( len > 0 ); // ファイルを閉じる // close(fd); if ( len == 0 ) return 0; else return 3; }
実行結果はこちら。
[itotto@ ~/]$ cat samplefile.dat hoge hoge fuga fuga foo foo bar bar [itotto@ ~/]$ gcc -o dataread dataread.c && ./dataread samplefile.dat hoge hoge fuga fuga foo foo bar bar [itotto@ ~/]$
open()の返却値を格納しているfd(int型)をファイルディスクリプタと呼びます。
ファイルディスクリプタはLinux Kernelがファイルを管理するための情報を格納しておく構造体の番号です。そのため、ファイル操作を行う場合には操作したいファイルのファイルディスクリプタがいくつなのかということを知っておく必要があります。これの番号を介してファイル操作対象を指定します。
また、open()の第二引数で指定するフラグ(上のソースだとO_RDONLY)はファイルを開く時にどのようなモードで開くのかを指定するフラグです(fcntl.hに定義)。よく使うフラグは以下のとおりです。
フラグ名 | 役割 |
---|---|
O_RDONLY | ファイルを読出専用で開く事を要求 |
O_WRONLY | ファイルを書込専用で開く事を要求 |
O_RDWR | ファイルを読書容量で開く事を要求 |
また、このフラグについて追加で指定出来るフラグがあります。
追加用のフラグ名 | 意味 |
---|---|
O_CREAT | ファイルが存在しないと作成する O_RDONLYと併用しても大丈夫 |
O_EXCL | ファイルがない場合には作成するが、ある場合にはエラーになる (該当処理でファイルが作成される事を保証する際に使う) |
O_TRUN | ファイルが既にある場合、その内容を削除する |
O_APPEND | 追加モードでファイルを開く |
追加で指定する場合には上記フラグに対して論理和を取って指定します。
[例]
// ファイルを書込用で、かつ追加モードで開く // open("/home/itotto/hogehoge.txt",O_WRONLY|O_APPEND);
さて。
この追加用のフラグのO_CREATを指定した場合にはファイルのpermissionを第三引数として指定する必要があります。
mode | 値 | 意味 |
---|---|---|
S_IRWXU | 00700 | 所有者の読書実行を許可 |
S_IRUSR | 00400 | 所有者の読み込みを許可 |
S_IREAD | 〃 | 〃 |
S_IWUSR | 00200 | 所有者の書き込みを許可 |
S_IWRITE | 〃 | 〃 |
S_IXUSR | 00100 | 所有者の実行を許可 |
S_IEXEC | 〃 | 〃 |
S_IRWXG | 00070 | グループの読書実行を許可 |
S_IRGRP | 00040 | グループの読み込みを許可 |
S_IWGRP | 00020 | 所有者の書き込みを許可 |
S_IXGRP | 00010 | 所有者の実行を許可 |
S_IRWXO | 00007 | 上記以外の読書実行を許可 |
S_IROTH | 00004 | 上記以外の読み込みを許可 |
S_IWOTH | 00002 | 上記以外の書き込みを許可 |
S_IXOTH | 00001 | 上記以外の実行を許可 |
UNIXのファイルパーミッションの考えを理解していれば特に悩むところはありませんが、プログラムを実行したユーザのumaskの影響を受ける点については注意してください。
次回はファイル入出力からさらに掘りさげてまとめます。
次へ進む