UNIXプログラミング入門~ファイル編(1/2)~

c/c++でunix系osプログラミングを行うときに使うunistd.hやその周辺のライブラリのお話です。
このメモでは、ファイルの入出力に関して取り上げます。

ファイルを開く-open関数-

通常c/c++でファイル操作を行うときはfopen関数を利用しますが、今回はそれよりももっとシステムコールに近いopen関数を利用します。

利用するにはfcntl.hをインクルードします。

#include <fcntl.h>

open関数のプロトタイプは以下のように宣言されています。

int open(const char* pathname, int flags[, int mode]);

第一引数pathnameには開く対象のファイルのパスを指定します。
絶対パスでも相対パスでも構いません。

第二引数flagsにはO_RDONLY, O_RDWR, O_WRONLYなどファイルをどのように利用するかを指定します。
それぞれfopen関数の"r", "r+", "w"に相当します。
O_RDONLY
ファイルを読み込み専用で開きます。

O_RDWR
ファイルを読み書き両方ができるように開きます。

O_WRONLY
ファイルを書き込み専用で開きます。

また上記に加え、O_APPEND, O_CREAT等をor(|)で結合して指定することもできます。
O_APPEND
ファイルを開いてファイルポインタをファイルの最後に移動します。
ファイルに追記を行うときなどに利用します。

open("hoge/hoge", O_WRONLY | O_APPEND)

のように利用することが多いと思います。

O_CREAT
ファイルが存在していないとき新しくファイルを作成して開きます。
既にファイルが存在しているときは意味を持ちません。

open("hoge/hoge", O_WRONLY | O_CREAT)

のように利用することが多いと思います。

この場合は、第一引数で指定されたファイルを書き込み専用で開いて、ファイルが存在していなければ新しく作成して開きます。

O_TRUNC
ファイルが存在していればサイズを0にして開きます。
要は、上書きです。

open("hoge/hoge", O_WRONLY | O_CREAT | O_TRUNC)

のように利用することが多いと思います。

この場合は、第一引数で指定されたファイルを書き込み専用で開いて、ファイルが存在していなければ新しく作成し、存在していれば大きさを0にして開きます。

O_BINARY O_TEXT
それぞれ、バイナリモード、テキストモードでファイルを開きます。
バイナリモードとテキストモードでは、改行コード等の扱いが異なることがあります。

第三引数modeは、 パーミッションの指定です。
基本的には指定しないことが多いと思います。

S_IRWXU
00700 ユーザー (ファイルの所有者) に読み込み、書き込み、 実行の許可がある。 S_IRUSR 00400 ユーザーに読み込みの許可がある。 S_IWUSR 00200 ユーザーに書き込みの許可がある。 S_IXUSR 00100 ユーザーに実行の許可がある。 S_IRWXG 00070 グループに読み込み、書き込み、実行の許可がある。 S_IRGRP 00040 グループに読み込みの許可がある。 S_IWGRP 00020 グループに書き込みの許可がある。 S_IXGRP 00010 グループに実行の許可がある。 S_IRWXO 00007 他人 (others) に読み込み、書き込み、実行の許可がある。 S_IROTH 00004 他人に読み込みの許可がある。 S_IWOTH 00002 他人に書き込みの許可がある。 S_IXOTH 00001 他人に実行の許可がある。

open関数は、成功した場合には0以上の整数が戻り値となります。

この時の戻り値はファイルディスクリプタと呼ばれ、開かれたファイルに対する操作はすべてこのファイルディスクリプタを指定して行います。

ファイルを閉じる-close関数-

ファイルを開いたら閉じなければなりません。
fopenで開いたファイルをfcloseで閉じるのと同様、openで開いたファイルはclose関数で閉じます。

利用するにはunistd.hをインクルードします。

#include <unistd.h>

close関数のプロトタイプは以下のように宣言されています。

int close(int fd);

引数には、open関数で取得したファイルディスクリプタ(open関数の戻り値)を渡します。

ファイルを閉じることに成功したら0が、失敗した場合には-1が返ってきます。

利用例

#include <fctrl.h>  
#include <unistd.h>
#include <stdio.h>

int main(int argc, char const* argv[])
{
    int fd;    
    if ((fd = open("hoge/hoge", O_RDONLY)) < 0) {
        printf("ファイルを開けませんでした\n");
        return -1;
    }
    /* 何かしらの処理*/
    close(fd);
    return 0;
}

まとめ

  • fcntl.hunistd.hをインクルード
  • open()を利用してファイルを開く
  • 使い終わったファイルはclose()で閉じる
  • ファイルへの操作はファイルディスクリプタを指定して行う

次回は、readwriteを行ってみようと思います。

つぶやき

ファイルを開くのとファイルを閉じるのでヘッダーファイルが別々になっているのにはなんか違和感を感じますが、何か理由があるんですかね?
知ってる人がいたら教えてください。