ページ 1 / 1
フォルダの中にあるpngファイルの数と名前を取得したい
Posted: 2014年5月04日(日) 21:20
by wasawasa
こんにちは、いつもお世話になっています。
X個のpngファイルを含めたY個のファイルが入っている「Folder」という名前のフォルダがプロジェクトファイルと同じフォルダの中にあったとして、Folderフォルダの中にあるpngファイルの数をint型の変数に、Folderフォルダ内のpngファイル全ての名前をCHAR型の変数に格納するとしたらどうすればいいでしょうか?
特定のフォルダ内の全てのpngファイルを読み込むプログラムを有象無象のファイルが混ざっている状況も想定して記述したいのですが、名前も数も分からない場合はどうしたらいいのか見当が付かないので困っています。
何かいい方法は無いでしょうか?どなたかよろしくお願いします。
Re: フォルダの中にあるpngファイルの数と名前を取得したい
Posted: 2014年5月04日(日) 23:03
by YuO
OS等,どのような環境でしょうか。
また,「フォルダ」であって「ディレクトリ」ではないのですね。
オフトピック
フォルダとディレクトリは別物であることがあるので (e.g. Windows)。
Re: フォルダの中にあるpngファイルの数と名前を取得したい
Posted: 2014年5月05日(月) 10:45
by wasawasa
>>YuOさん
すみません、書き忘れていました。
OSはWindows7で、プログラミングに使用しているソフトはMicrosoft Visual C++ 2008 Express Editionです。
Windowsでのフォルダとディレクトリの違いは説明見てもよく分かりませんでした。
Re: フォルダの中にあるpngファイルの数と名前を取得したい
Posted: 2014年5月05日(月) 12:29
by なないと
ネットで少し調べればフォルダ内のファイル名を取得するプログラムは
簡単にでてくるのですが、何から何まで分からないということはないと思います。
少し作ってみてから再度質問してみたらどうでしょうか?
Re: フォルダの中にあるpngファイルの数と名前を取得したい
Posted: 2014年5月05日(月) 13:02
by Dixq (管理人)
FindFirstFile
と
FindNextFile
を用いることでファイル名一覧が取得できますよ。
http://d.hatena.ne.jp/s-kita/20100129/1264776052
そこから欲しいファイルだけフィルタリングすればOKです。
Re: フォルダの中にあるpngファイルの数と名前を取得したい
Posted: 2014年5月05日(月) 17:58
by YuO
すでにDixq (管理人)さんが
FindFirstFileと
FindNextFileを紹介されているので,ディレクトリ下のファイルについては省略します。
wasawasa さんが書きました:Windowsでのフォルダとディレクトリの違いは説明見てもよく分かりませんでした。
ディレクトリは完全に物理的に存在する物です。
それに対して,フォルダーはディレクトリを含みますが,物理的に存在しない,例えば「ネットワーク」フォルダ (
FOLDERID_NetworkFolder,
CSIDL_NETWORK) も含みます。
ZIPやCABもフォルダーとなります。
エクスプローラーで表示される階層構造に含まれる物は,だいたいフォルダーです。
フォルダーを相手にするのであれば,
SHGetDesktopFolderあたりを元に,
IShellFolderとお友達になりながら調べていくことになるかと思います。
あとは,
SHGetIDListFromObjectとか
SHGetPathFromIDListとかでしょうか。
最終的にはディレクトリーに帰結させてFindFirstFile系で探した方が楽だとは思います。
オフトピック
EnumObjectsで非フォルダーを列挙させて,も可能ですが,FindFirstFileと違いワイルドカードによるフィルタリングができないので……。
► スポイラーを表示
回答を作るために,デスクトップからのフォルダーを全部列挙するコードを書いたので,もったいないですし貼り付けます。
とりあえず,「フォルダー」とは何かがわかるかと思います。
リソース管理が面倒なので,簡易のRAIIクラスを用意しています。
# インラインでもいくつかRAIIクラスがあります。2010以降なら
unique_ptrとカスタムデリーターで処理できるものですが……。
コード:
#include <Windows.h>
#include <ShlObj.h>
#include <Shlwapi.h>
#include <iostream>
#include <iomanip>
#include <locale>
#include <exception>
#include <string>
#include <conio.h>
#pragma comment(lib, "shlwapi")
// COM例外
class com_exception : std::exception
{
private:
const ::HRESULT hr_;
public:
com_exception(::HRESULT hr) : hr_(hr) { }
::HRESULT get() const { return hr_; }
};
// COMポインタのRAII用実装ベース
template <typename T> class com_pointer_impl
{
protected:
T * ptr_;
com_pointer_impl & operator= (const com_pointer_impl &);
// HRESULTがFAILEDならcom_exceptionを投げる為の補助関数
void test(::HRESULT hr) { if (FAILED(hr)) throw com_exception(hr); }
public:
com_pointer_impl() : ptr_(0) {}
com_pointer_impl(T * ptr) : ptr_(ptr) {}
com_pointer_impl(const com_pointer_impl & obj) :ptr_(obj.ptr_)
{
// コピー時には参照カウントをインクリメントする
if (ptr_ != 0) ptr_->AddRef();
}
~com_pointer_impl()
{
// 破棄時に参照カウントをデクリメントする
if (ptr_ != 0) ptr_->Release();
ptr_ = 0;
}
T * get() const { return ptr_; }
};
// COMポインタのRAII用実装
template <typename T> struct com_pointer : private com_pointer_impl<T>
{
typedef T Type;
com_pointer() : com_pointer_impl() {}
com_pointer(Type * ptr) : com_pointer_impl(ptr) {}
com_pointer(const com_pointer & obj) : com_pointer_impl(obj) {}
template <typename U> com_pointer(const com_pointer<U> & obj) : com_pointer_impl()
{
// COMポインタのキャストはQueryInterfaceをする
if (obj.get() != 0)
{
test(obj->QueryInterface(&ptr_));
}
}
Type * operator -> () { return ptr_; } // 直接COMのメソッドを呼び出す
operator Type** () { return &ptr_; } // ファクトリ系メソッドに渡すための補助関数
Type *& get() { return ptr_; } // ファクトリ系メソッドに渡すための補助関数
};
template <> struct com_pointer<::IShellFolder> : private com_pointer_impl<::IShellFolder>
{
typedef ::IShellFolder Type;
com_pointer() : com_pointer_impl() {}
com_pointer(Type * ptr) : com_pointer_impl(ptr) {}
com_pointer(const com_pointer & obj) : com_pointer_impl(obj) {}
template <typename U> com_pointer(const com_pointer<U> & obj) : com_pointer_impl()
{
// COMポインタのキャストはQueryInterfaceをする
if (obj.get() != 0)
{
test(obj->QueryInterface(&ptr_));
}
}
Type * operator -> () { return ptr_; } // 直接COMのメソッドを呼び出す
operator Type** () { return &ptr_; } // ファクトリ系メソッドに渡すための補助関数
Type *& get() { return ptr_; } // ファクトリ系メソッドに渡すための補助関数
// IShellFolder::GetDisplayNameOfを簡易呼び出し用関数
std::wstring GetDisplayNameOf(SHGDNF uFlags)
{
return GetDisplayNameOf(0, uFlags);
}
std::wstring GetDisplayNameOf(PCUITEMID_CHILD pidl = 0, SHGDNF uFlags = SHGDN_NORMAL)
{
::STRRET sr;
test(ptr_->GetDisplayNameOf(pidl, uFlags, &sr));
class Releaser
{
private:
::LPWSTR str_;
public:
Releaser() :str_(0) {}
~Releaser()
{
if (str_ != 0) ::CoTaskMemFree(str_);
}
::LPWSTR get() const { return str_; }
::LPWSTR * get_pointer() { return &str_; }
} temp;
test(::StrRetToStrW(&sr, 0, temp.get_pointer()));
return temp.get();
}
// IShellFolder::EnumObjectsを簡易呼び出し用関数
com_pointer<::IEnumIDList> EnumObjects(SHCONTF grfFlags)
{
com_pointer<::IEnumIDList> result;
test(ptr_->EnumObjects(0, grfFlags, result));
return result;
}
};
// フォルダーを表示
void show_shell_folder(com_pointer<::IShellFolder> folder, int indent)
{
std::wstring indent_string(indent * 2, L' ');
com_pointer<::IEnumIDList> enum_id_list = folder.EnumObjects(SHCONTF_FOLDERS);
if (enum_id_list.get() == 0)
{
return;
}
// フォルダーの列挙
while (true)
{
// LPITEMIDLISTを確実にCoTaskMemFreeする為のヘルパークラス
class item_id_list
{
private:
::LPITEMIDLIST id_list;
public:
item_id_list() : id_list(0) {}
~item_id_list()
{
if (id_list != 0)
{
::CoTaskMemFree(id_list);
}
}
::LPITEMIDLIST get() { return id_list; }
::LPITEMIDLIST * get_pointer() { return &id_list; }
} id_list;
::HRESULT hr = enum_id_list->Next(1, id_list.get_pointer(), 0);
if (hr == S_FALSE) break;
if (FAILED(hr)) throw com_exception(hr);
com_pointer<::IShellFolder> sub_folder;
::IShellFolder * & sub_folder_pointer = sub_folder.get();
hr = folder->BindToObject(id_list.get(), 0, IID_PPV_ARGS(&sub_folder_pointer));
if (FAILED(hr)) throw com_exception(hr);
std::wstring name = folder.GetDisplayNameOf(id_list.get());
std::wcout << indent_string << name << std::endl;
try
{
show_shell_folder(sub_folder, indent + 1);
}
catch (const com_exception & e)
{
// ※Ad-hocな例外対処なので注意
if (
e.get() == E_ACCESSDENIED ||
e.get() == E_INVALIDARG ||
e.get() == REGDB_E_IIDNOTREG ||
e.get() == HRESULT_FROM_WIN32(ERROR_CANCELLED) ||
e.get() == HRESULT_FROM_WIN32(ERROR_NOT_READY) ||
e.get() == HRESULT_FROM_WIN32(ERROR_BAD_NETPATH) ||
e.get() == HRESULT_FROM_WIN32(ERROR_BAD_FORMAT) ||
e.get() == HRESULT_FROM_WIN32(ERROR_NETWORK_ACCESS_DENIED) ||
false
)
{
continue;
}
throw;
}
}
}
int main(void)
{
std::wcout.imbue(std::locale("", std::locale::ctype));
struct com_initialize
{
com_initialize() { ::CoInitialize(0); }
~com_initialize() { ::CoUninitialize(); }
} com_initializer_;
com_pointer<::IShellFolder> desktop;
::SHGetDesktopFolder(desktop);
try
{
std::wcout << desktop.GetDisplayNameOf() << std::endl;
show_shell_folder(desktop, 1);
}
catch (com_exception & e)
{
std::wcout << std::showbase << std::hex << std::setw(8) << (int)e.get() << std::endl;
return (int)e.get();
}
return 0;
}
オフトピック
ZIPやCABの中まで列挙するので,ファイルも列挙する (SHCONTF_NONFOLDERS) のは勘弁してください……。
テスト実行でいくら時間がかかるかわからない……。
上記も,全部の列挙が終わったわけではないです……。
Re: フォルダの中にあるpngファイルの数と名前を取得したい
Posted: 2014年5月06日(火) 17:51
by wasawasa
>>Dixq (管理人)さん
>>YuOさん
GetModuleFileName()で実行ファイルのパスを取得してから、それを元に目当てのフォルダのパスを組み立ててFindFirstFileとFindNextFileで読み込む、という方法でできるようになりました。ありがとうございます。