ファイル検索

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら

ファイル検索

#1

投稿記事 by » 13年前

マイコンピュータにあるすべてのドライブ/ディレクトリから指定したファイルを検索し、そのフルパスを取得するプログラムを作成したいです。

感じ的にはWindowsのスタートの中にある「検索」のような感じです。

今のところCUIでの作成を考えているのですが、scanf()などでファイル名を入力してもらい、
プログラムでCドライブ、Dドライブ、その他のドライブからディレクトリ/ファイル名を見つけたいです。

何か簡単に出来そうなAPIありませんか?
ちなみに2000,XP,Vista,7に対応していればいいかな?って思ってます。

開発環境はVC++2010です。

ぬっち
記事: 105
登録日時: 13年前
連絡を取る:

Re: ファイル検索

#2

投稿記事 by ぬっち » 13年前

やはりWin32APIではないでしょうか?
私もこの前フォルダ内のファイルを検索するプログラムを作成したのですが、その時もWin32APIを使いました。

http://www.geocities.jp/ky_webid/win32c/054.html
ここあたりが参考になるのではないでしょうか?

Re: ファイル検索

#3

投稿記事 by » 13年前

ぬっち さんが書きました:やはりWin32APIではないでしょうか?
私もこの前フォルダ内のファイルを検索するプログラムを作成したのですが、その時もWin32APIを使いました。

http://www.geocities.jp/ky_webid/win32c/054.html
ここあたりが参考になるのではないでしょうか?
やっぱりFindFirstFileになりますかね?
私も何回かFindFirstFileは使ったことありますが、それは
C:\C:\Program Files\フォルダ名\*.ini
のようにある程度ディレクトリがわかってたので使えましたが
今回のようにドライブもディレクトリもわからないとなるとどうなるのでしょうか?

逆にたとえば私がtest.searchmeというファイルを適当なドライブ\フォルダに作成したとし、
それを探すプログラムを作成してくださいと言ったらすぐに作れますか?
※たとえ話なのでホントに作る作らないは別としてです。

アバター
bitter_fox
記事: 607
登録日時: 13年前
住所: 大阪府

Re: ファイル検索

#4

投稿記事 by bitter_fox » 13年前

豹 さんが書きました: プログラムでCドライブ、Dドライブ、その他のドライブからディレクトリ/ファイル名を見つけたいです。

何か簡単に出来そうなAPIありませんか?
ファイルとディレクトリの検索及びディレクトリ等の変更は、以下の関数で可能です。
long _findfirst( char* filespec, _finddata_t* fileinfo ) // ファイルの検索をする際最初に呼び出す(この関数もファイルを検索する)
int _findnext( long handle, _finddata_t* fileinfo ) // ファイルを検索する(第一引数にはfindfirstの戻り値を指定する)
int _findclose( long handle ) // ファイルの検索が終了したらこの関数を呼び出す(第一引数にはfindfirstの戻り値を指定する)

int _chdrive( int drive ) // カレントディスクを変更します
int _chdir( const char* dirname ) // カレントディレクトリを変更します
char* _getcwd( char* buffer, int maxlen ) // カレントドライブのカレントディレクトリを取得します
[参考]
http://www5c.biglobe.ne.jp/~ecb/c/15_06.html

取りあえずこんな感じですがいかがでしょうか??
再帰的に検索するというのが一般的でしょうね。
[hr][修正]参考URLがリンクされてなかったので修正。
最後に編集したユーザー bitter_fox on 2010年12月14日(火) 05:52 [ 編集 1 回目 ]

アバター
bitter_fox
記事: 607
登録日時: 13年前
住所: 大阪府

Re: ファイル検索

#5

投稿記事 by bitter_fox » 13年前

豹 さんが書きました: やっぱりFindFirstFileになりますかね?
私も何回かFindFirstFileは使ったことありますが、それは
C:\C:\Program Files\フォルダ名\*.ini
のようにある程度ディレクトリがわかってたので使えましたが
今回のようにドライブもディレクトリもわからないとなるとどうなるのでしょうか?
僕があげた、関数群でも同様です。

今回のようにドライブもディレクトリもわからなく網羅的にやる場合は以下のようになります。

0.カレントドライブからカレントディレクトリを選択します(この場合は、一番上からすべてを検索するのでC:\)
1.カレントディレクトリのファイルを続きから(初めてのディレクトリの場合は、最初から)検索します。
2-1.ファイルが見つかったら
それがお目当てのファイルだった場合はカレントディレクトリを取得して見つかったということを表示する
お目当てでなければスルーする。そして、1に戻ります。
2-2.ディレクトリが見つかったら
そのディレクトリをカレントディレクトリにして1に戻ります。

3.もうこれ以上ディレクトリとファイルがなければ、ひとつ上のディレクトリをカレントディレクトリにして1に戻ります。
3'.カレントディレクトリが、C:\などのトップディレクトリの場合は、検索を終了。

この操作を、すべてのドライブにしてあげます。

[hr][修正]ループになっていなかったので修正
[追記・編集]すべてのドライブを考慮してなかったので追記、アルゴリズムの一部を編集

Re: ファイル検索

#6

投稿記事 by » 13年前

コード:

#include <stdio.h>
#include <windows.h>

#pragma comment(lib,"kernel32.lib")

int main()
{
	HANDLE hFind;
	WIN32_FIND_DATA fd;
	FILETIME ft;
	SYSTEMTIME st;

	DWORD buf_size,cnt;

	UINT check;

	char buf[1000];
	char data[1000];

	int flag,flag2;

	buf_size = GetLogicalDriveStrings(1000,buf);

	cnt = 0;

	while(cnt < buf_size)
	{
		check = GetDriveType(&buf[cnt]);

		flag = 0;

		if(check == DRIVE_FIXED)
		{
			sprintf(data,"%s*",&buf[cnt]);

			hFind = FindFirstFile(data,&fd);

			if(hFind == INVALID_HANDLE_VALUE)
			{
				printf("検索失敗\n");
			}
			else
			{
				do
				{
					if((strcmp(fd.cFileName,".") && strcmp(fd.cFileName,"..")) != 0)
					{
						if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
						{
							printf("フォルダ => %s%s\n",&buf[cnt],fd.cFileName);
						}
						else
						{
							printf("ファイル => %s%s\n",&buf[cnt],fd.cFileName);
						}
					}
				}
				while(FindNextFile(hFind, &fd));
			}
		}

		cnt += lstrlen(&buf[cnt])+1;
	}

	getch();
}
ここまでは作成したのですが、フォルダが見つかった場合
if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
printf("フォルダ => %s%s\n",&buf[cnt],fd.cFileName);
}
ここで今度は
sprintf(data,"%s%s\\*",&buf[cnt],fd.cFileName);
hFind = FindFirstFile(data,&fd);
とするわけですよね?
それでさらにフォルダが見つかった場合同じようにしてとやってると頭が混乱してきました。

アバター
bitter_fox
記事: 607
登録日時: 13年前
住所: 大阪府

Re: ファイル検索

#7

投稿記事 by bitter_fox » 13年前

豹 さんが書きました: sprintf(data,"%s%s\\*",&buf[cnt],fd.cFileName);
hFind = FindFirstFile(data,&fd);
とするわけですよね?
それでさらにフォルダが見つかった場合同じようにしてとやってると頭が混乱してきました。
確かにmain関数ひとつに突っ込んだら、非常に混乱してきますしカオスなコードになってしまいます。
そこで検索部分を関数化してあげます。そしてその関数の中で、さらにその関数を呼んであげます。この手法を再帰呼び出しと言います。
こうすることによって無限(現実世界では無限はないですが・・・)の彼方にあるファイルにまでたどり着くことができます。(数学的帰納法的ですね)
以下に例を示します。

コード:


#include <stdio.h>
#define MAX 3

int a[MAX][5] = 
{
	{1 ,10 , 0 ,3 ,4}, 
	{54, 0, 32, 43, 433},
	{432, 5463, 432, 0, 5432}
};

int main()
{
	func(0);

	return 0;
}

int func(int n)
{
	int counter = 0;

	if (n == MAX)
	{
		return 0;
	}

	while (counter < 5)
	{
		if (a[n][counter] == 0) // 今の要素が0だったら
		{
			func(n+1); // もうひとつ深く潜る
		}
		else
		{
			printf("%*s%d:%d\n", 4*n, "", a[n][counter], n);
		}

		counter++;
	}

	return 0;
}   
昨日からずっと起きてるので、まともなコメントが思い浮かば無いので、一度実行してみてください。
非常にファイル検索に似た物となってるはずです。
これは、配列でやってるのでスマートではない(定数を書いているので非動的)ですが、FindNextFileなどの、これ以上存在するかどうかを教えてくれるものをうまく使えばスマートなコードで、はるか彼方のファイルまで網羅的に検索できます。
[hr][追記]
return 0;が二箇所抜けていたので追加しました。
[修正]再帰==>再帰呼び出し
[追記]無限のところとスマートのところを少々追記

Re: ファイル検索

#8

投稿記事 by » 13年前

bitter_fox さんが書きました: 確かにmain関数ひとつに突っ込んだら、非常に混乱してきますしカオスなコードになってしまいます。
そこで検索部分を関数化してあげます。そしてその関数の中で、さらにその関数を呼んであげます。この手法を再帰呼び出しと言います。
こうすることによって無限(現実世界では無限はないですが・・・)の彼方にあるファイルにまでたどり着くことができます。(数学的帰納法的ですね)
以下に例を示します。
ありがとうございます。
とてもわかりやすい例を教えていただけたので無事に完成しました。
「再帰呼び出し」とても便利ですね。
言葉は知っていましたが今まで使い方もわからず、
なくてもプログラムできるだろうと思ってましたが
すごく使える手法ですね。
これから先いろんなところで使えそうです。
勉強になりました。

閉鎖

“C言語何でも質問掲示板” へ戻る