ディレクトリの操作
ファイル処理9
ファイルに続き、ディレクトリ(フォルダ)に対する操作をまとめます。
なお、ディレクトリ名の変更はその他のファイル操作を参照してください。
ファイルというのはOSや他の様々なプログラムからアクセスされる可能性があります。
他のプログラムが操作中のファイルに対する処理はエラーが発生する可能性があります。
実際のプログラムではエラー発生時の処理を適切に行う必要があります。
このページで説明する関数はすべてC言語標準関数ではありません。
コンパイラによっては使用できないものもあります。
ディレクトリ(フォルダ)作成
ディレクトリの作成にはmkdir
関数(_mkdir
関数)を使用します。
_mkdir
関数はVisual Studioでのみ使用可能です。
mkdir関数
mkdir
関数の使用には#include <sys/stat.h>
が必要です。
#include <stdio.h>
#include <sys/stat.h>
int main()
{
const char *dir = "./test";
if (mkdir(dir, 0777) == 0)
printf("ディレクトリ%sを作成しました。\n", dir);
else
printf("ディレクトリ%sを作成できませんでした。\n", dir);
getchar();
}
-
int mkdir(
const char *dirname
mode_t permission
); -
ディレクトリdirnameをパーミッションpermissionの設定で作成する。
成功した場合は0を、失敗した場合は0以外を返す。
上記コードは相対パスで、実行ファイルと同じ場所に「test」という名前のディレクトリを作成しています。
すでに同名のディレクトリが存在する場合は作成に失敗します。
プログラムをVisual Studio上から実行している場合はプロジェクトファイルのあるフォルダが相対パスの起点となります。
(実行ファイルやソリュージョンファイルのあるフォルダではない)
第二引数はパーミッションの設定を8進数で指定しています。
パーミッションというのはUNIX系OSで採用されている、ファイルやディレクトリに対するアクセス権限の設定です。
第二引数の数値の意味は、まず先頭が8進数リテラルを表す「0」です。
続いてOwner権限、Group権限、Other権限の順で指定で、「4」で読み込み、「2」で書き込み、「1」で実行の権限を表します。
(「0」は権限なし)
読み込みと実行の許可を与える場合は「4+1」で「5」を指定します。
(コンパイラによってはこれらの定数も用意されています。)
ただしumask値の影響を受けます。
Windowsユーザーにはなじみのないものかと思いますが、Windows上での実行においては(たぶん)意味のない指定です。
mkdir
関数は、ディレクトリの階層構造を一気に作成することはできません。
階層構造の上位ディレクトリが存在しない場合は実行に失敗します。
#include <stdio.h>
#include <sys/stat.h>
int main()
{
const char *dir = "./test/abc";
//「test」というディレクトリが存在しない場合
//「abc」フォルダは作成できず
//mkdir関数は失敗する
if (mkdir(dir, 0777) == 0)
printf("ディレクトリ%sを作成しました。\n", dir);
else
printf("ディレクトリ%sを作成できませんでした。\n", dir);
getchar();
}
_mkdir関数
_mkdir
関数を使用するには#include <direct.h>
が必要です。
direct.h
はVisual Studioでのみ使用できるヘッダなので、以下のコードはVisual Studio以外では動作しません。
#include <stdio.h>
#include <direct.h>
int main()
{
const char *dir = "./test";
if (_mkdir(dir) == 0)
printf("ディレクトリ%sを作成しました。\n", dir);
else
printf("ディレクトリ%sを作成できませんでした。\n", dir);
getchar();
}
-
int _mkdir(
const char *dirname
); -
ディレクトリdirnameを作成する。
成功した場合は0を、失敗した場合は0以外を返す。
使い方はmkdir
関数とほぼ同じで、第二引数のパーミッションの指定がないだけです。
errno
mkdir
関数は処理に失敗した場合にerrno
を書き換えます。
より正確にエラー処理をする場合はこれを利用します。
errno
はC言語の関数が処理に失敗した場合に、失敗した理由が格納される特殊なグローバル値です。
(処理が失敗してもerrno
を書き換えない関数も多くあります)
ただしこの関数自体がC言語標準ではないため、設定される値も各コンパイラの実装によります。
以下の二つは大体共通しているようです。
- EEXIST
- 指定のディレクトリが既に存在する
- ENOENT
- 指定のパスが存在しない
errno
を使用するために<errno.h>
をインクルードします。
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
int main()
{
const char* dir = "./test/abc";
//errnoを0に戻しておく
errno = 0;
if (mkdir(dir, 0777) == 0) {
printf("ディレクトリ%sを作成しました。\n", dir);
}
else {
if(errno == EEXIST)
printf("ディレクトリ%sは既に存在します。\n", dir);
else if(errno == ENOENT)
printf("パス%sが存在しません。\n", dir);
else
printf("ディレクトリ%sを作成できませんでした。\n", dir);
//errnoを0に戻しておく
errno = 0;
}
getchar();
}
errno
はプログラム起動直後は0がセットされているので今回のコードではあらかじめ0で初期化する必要はありません。
errno
は、関数が成功した場合にその値がどうなるかは規定されていません。
関数が成功したら0にセットされるわけではありませんし、関数が成功してもerrno
の値が0以外にセットされることはルール上あり得ます。
そのため、mkdir
関数のように関数の成否が戻り値で受け取れる場合は、まず戻り値でエラーの有無をチェックし、エラー値が返された場合にerrno
のでエラーの詳細をチェックします。
関数が正常な処理を行った場合でもerrno
は書き換わる可能性があるため、ある関数のエラーチェックをする場合はその関数を実行する直前でerrno
を0に戻しておき、実行の直後でerrno
の値を調べる必要があります。
それをしない場合のerrno
の値は不明なので、使用できません。
ディレクトリの削除
ディレクトリを削除するにはrmdir
関数(_rmdir
関数)を使用します。
rmdir
関数は「#include <unistd.h>
」が必要です。
_rmdir
関数は「#include <direct.h>
」が必要です。
(Visual Studio専用)
#include <stdio.h>
#include <unistd.h>
int main()
{
const char *dir = "./test";
if(rmdir(dir) == 0)
printf("ディレクトリ%sを削除しました。\n", dir);
else
printf("ディレクトリ%sを削除できません。\n", dir);
getchar();
}
-
int rmdir(
const char *dirname
); -
ディレクトリdirnameを削除する。
成功した場合は0を、失敗した場合は0以外を返す。
rmdir
関数も_rmdir
関数も使い方は同じです。
ディレクトリを削除するには、そのディレクトリが空である必要があります。
ディレクトリ内にファイルやフォルダが残っている場合は削除に失敗します。
ディレクトリの存在確認
ディレクトリの存在確認にはstat
関数を使用します。
(stat
関数に関してはファイルサイズの取得を参照)
#include <stdio.h>
#include <sys/stat.h>
int main()
{
const char *dir = "C:\\ABC";
struct stat statBuf;
if (stat(dir, &statBuf) == 0)
printf("ディレクトリ%sは存在します。\n", dir);
else
printf("ディレクトリ%sは存在しません。\n", dir);
getchar();
}
stat
関数にはディレクトリも指定できます。
stat
関数が成功すればディレクトリが存在するということになります。
direct.hの他の関数
Visual Studioで使用できるヘッダdirect.h
には他にもいくつかのディレクトリ操作用の関数があります。
_getcwd関数
_getcwd
関数は、現在のワーキングディレクトリのパスを取得します。
_getdrive
は、現在のワーキングディレクトリのあるドライブを取得します。
#include <stdio.h>
#include <direct.h>
#define MAX_PATH 260
int main()
{
char buf[MAX_PATH];
printf("%s\n", _getcwd(buf, MAX_PATH));
printf("%d\n", _getdrive());
getchar();
}
C\:Visual Studio Project\test\Debug 3
-
char* _getcwd(
char *buffer
int bufferSize
); -
文字列bufferに現在のワーキングディレクトリのパスを格納する。
戻り値はbuffer。
取得されるパス文字列のサイズがbufferSizeを超えた場合はNULLを返す。
- int _getdrive();
-
現在のワーキングディレクトリのあるドライブを1~26の整数で返す。
数字はA~Zのドライブ文字に対応する。
ワーキングディレクトリとは実行ファイルが現在使用しているディレクトリ(フォルダ)のことです。
(カレントディレクトリ、作業フォルダとも言う)
ファイルの読み取りや書き込みなどで相対パスを指定した場合に、パスの起点として使用されるディレクトリです。
規定では実行ファイルのある場所がワーキングディレクトリとなります。
プログラムをVisual Studio上から実行している場合はプロジェクトファイルのあるフォルダが相対パスの起点となります。
(実行ファイルやソリュージョンファイルのあるフォルダではない)
_chdir関数、_chdrive関数
_chdir
関数は、現在のワーキングディレクトリを変更します。
_chdrive
関数は、現在のドライブを変更します。
-
int _chdir(
const char *dirname
); -
現在のワーキングディレクトリをdirnameに変更する。
成功した場合は0を、失敗した場合は-1を返す。
-
int _chdrive(
int drive
); -
現在のワーキングディレクトリのあるドライブをdriveに変更する。
driveは1~26の整数で、A~Zのドライブ文字に対応する。
成功した場合は0を、失敗した場合は-1を返す。
#include <stdio.h>
#include <direct.h>
#define MAX_PATH 260
int main()
{
char buf[MAX_PATH];
//ワーキングディレクトリを
//「C:/test」に変更
//指定のディレクトリが無ければ失敗
_chdir("C:/test");
printf("%s\n", _getcwd(buf, MAX_PATH));
//ワーキングドライブを
//Eドライブに変更
//Eドライブがなければ失敗
_chdrive(5);
printf("%s\n", _getcwd(buf, MAX_PATH));
getchar();
}
C:\test E:\
Windows環境に限定する場合、C言語関数よりもWindows APIを使用したほうがより高度な操作が可能です。
(→Windows API)