以下は目次です。
ある名前のファイルが、存在しているかどうかを知りたいとします。
現実問題として、このような処理にはあまり信頼性がありません。いくらファイルの存在を調べたところで、調べ終えた直後に、他のプログラムによって、ファイルが作られたり、消されたりする可能性があるからです。
その可能性が排除できないのなら、事前に存在を確認して、その結果に応じて処理を行うよりも、必要なときに普通にファイルを開いたり、作ったりしてみて、その結果に応じて処理を行う方が良いかもしれません。
一応、よく使われる手法を以下に示しますが、 どの方法を選んでも、このような問題には対応できませんし、 他の観点で問題を抱えていることもあります。
よく使われる手法の1つに、 C言語の標準ライブラリに含まれている fopen関数を使うものがあります。
fopen関数の第2引数を “r” にして、読み取りモードでオープンします。このモードの場合、指定したファイルが存在しないと失敗して、ヌルポインタを返すという仕様を利用します。
#include <stdio.h>
/*
ファイルの存在を確認する。
path: ファイルパス。
戻り値: 存在したら 0以外、存在しなければ 0
*/
int exist_file(const char* path)
{
FILE* fp = fopen(path, "r");
if (fp == NULL) {
return 0;
}
(fp);
fclosereturn 1;
}
int main(void)
{
if (exist_file("test.txt")) {
("存在します。");
puts}
else {
("存在しません。");
puts}
}
実行結果:
存在します。
この方法の問題は、fopen関数が「指定されたファイルが存在しない」以外の理由でも失敗し得るということです。 たとえば、ファイルの読み取り権限がない場合、読み取りモードでのオープンが行えないため失敗します。
非標準の関数ですが、 stat関数(→参考。Man page of STAT)を使う方法があります。
#include <stdio.h>
#include <sys/stat.h>
/*
ファイルの存在を確認する。
path: ファイルパス。
戻り値: 存在したら 0以外、存在しなければ 0
*/
int exist_file(const char* path)
{
struct stat st;
if (stat(path, &st) != 0) {
return 0;
}
// ファイルかどうか
// S_ISREG(st.st_mode); の方がシンプルだが、Visual Studio では使えない。
return (st.st_mode & S_IFMT) == S_IFREG;
}
int main(void)
{
if (exist_file("test.txt")) {
("存在します。");
puts}
else {
("存在しません。");
puts}
}
実行結果:
存在します。
stat関数は、ファイルの状態を調べる関数です。ファイルに関するさまざまな情報を、stat構造体に格納してもらい、各メンバの値を確認することで、状態を調べられます。
stat関数は成功すると 0 を、エラー発生時には -1 を返します。 このサンプルプログラムでは、どんなエラーでも、ファイルは存在しないものとして扱っていますが、 errno を調べることで、エラーの詳細な内容を判定できます。 ただ、エラーの内容を知ったところで、stat構造体に値を取得できていない以上、 「判定できなかった」という結果を得る程度のことしかできません。
Windows の場合は、 Windows API の PathFileExists関数(→Microsoft Docs を使用できます。
#include <Shlwapi.h>
#include <stdio.h>
#pragma comment(lib, "Shlwapi.lib")
/*
ファイルの存在を確認する。
path: ファイルパス。
戻り値: 存在したら 0以外、存在しなければ 0
*/
int exist_file(const char* path)
{
return PathFileExistsA(path);
}
int main(void)
{
if (exist_file("test.txt")) {
("存在します。");
puts}
else {
("存在しません。");
puts}
}
実行結果:
存在します。
PathFileExists関数を使用するには、Shlwapi.h
のインクルードと、Shlwapi.lib のリンクが必要です。
また、PathFileExists
は実際にはマクロになっていて、UNICODEマクロの定義の有無によって、
ANSI版(char型)の PathFileExistsA と、Unicode版(wchar_t型)の
PathFileExistsW のいずれかに置換されます。
上のサンプルプログラムでは、文字列を const char* で扱っているため、
PathFileExistsA の方を直接呼び出すようにしています。
return 0;
を削除(C言語編全体でのコードの統一)「NULL」よりも「ヌルポインタ」が適切な箇所について、「ヌルポインタ」に修正。
「VisualC++」という表現を「VisualStudio」に統一。
コンパイラの対応状況について、対応している場合は明記しない方針にした。
clang 3.7 (Xcode 7.3) を、Xcode 8.3.3 に置き換え。
新規作成。
Programming Place Plus のトップページへ
はてなブックマーク に保存 | Pocket に保存 | Facebook でシェア |
X で ポスト/フォロー | LINE で送る | noteで書く |
RSS | 管理者情報 | プライバシーポリシー |