フォルダの読み込み

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

フォルダの読み込み

#1

投稿記事 by ポリ » 16年前

音楽ゲームを作成しているのですが、曲の追加をする時今はMP3までのパスを指定しメモリに読み込ませ
再生しています。

曲の追加をする際に、STEPMANIAのようにフォルダに曲を追加して曲一覧として表示、再生させる方法は
あるのでしょうか?

御津凪

Re:フォルダの読み込み

#2

投稿記事 by 御津凪 » 16年前

Windows 環境であれば、 Windows API の FindFirstFile と FindNextFile を使って
フォルダ内のファイルやフォルダを検索することが出来ます。

簡単ながらコードを書いてみました。
ANSI・UNICODE両ビルド可、クロスコンパイル(Windowsのみ)に対応してみました。
(これを書いたPC環境にチェックするためのコンパイラが無いので、正しくビルド・実行できるかは分かりません。あしからず^^;)
#include <windows.h>
#include <shlwapi.h>
// #include <tchar.h> // 必要かも。

// shlwapi.lib をリンクする必要あり

// tcsicmp の定義マクロ
#ifndef tcsicmp
 #ifdef _tcsicmp
  #define tcsicmp _tcsicmp
 #else
  #endif
  #if defined(UNICODE) || defined(_UNICODE)
   #ifdef _MSC_VER
    #define tcsicmp(a,b) _wcsicmp(a,b)
   #else
    #define tcsicmp(a,b) wcsicmp(a,b)
   #endif
  #else
   #ifdef _MSC_VER
    #define tcsicmp(a,b) _stricmp(a,b)
   #else
    #define tcsicmp(a,b) stricmp(a,b)
   #endif
  #endif
 #endif
#endif

// 検索処理関数
void SearchMP3File( LPCTSTR str ){
    WIN32_FIND_DATA wfd;
    HANDLE h = FindFirstFile(str,&wfd);
    if(h == INVALID_HANDLE_VALUE){ // パスが存在しない
        return;
    }
    do{
        if((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0 && // パスがフォルダでないもので、
            tcsicmp(PathFindExtension(wfd.cFileName),TEXT(".mp3")) == 0) // 拡張子が".mp3"のファイル
        {
            TCHAR buf[PATH_MAX];
            // 検索ディレクトリパスとファイルパスを結合
            PathCombine(buf,str,wfd.cFileName);
            // ここで buf には、MP3ファイルへのパスが入った状態。
            // 後は何らかの処理をここに入れる
        }
    }while(FindNextFile(h,&wfd)); // 次のパスを検索

    FindClose(h); // 検索ハンドルを閉じる
}
環境が限定的なら、
定義マクロはバッサリ切って直接書けば良いです。

lbfuvab

Re:フォルダの読み込み

#3

投稿記事 by lbfuvab » 16年前

うちの環境(WinXP,VC++2008EE)と仮定しています。

ディレクトリの選択 :SHBrowseForFolder、SHGetPathFromIDList、CoTaskMemFree
ディレクトリ内の検索:SetCurrentDirectory、GetCurrentDirectry、FindFirstFile、FindNextFile
MP3の再生?     :Dxライブラリ or MCI

↑のあたりですかね。

ポリ

Re:フォルダの読み込み

#4

投稿記事 by ポリ » 16年前

回答ありがとうございます。
環境はWindowsなのですが、DXライブラリのみでの作成で
WinAPIについては知識不足で・・・
せっかく回答をいただいたので、それを元にいろいろと調べてみます。

ちなみにDXライブラリとC言語だけでは実装は不可なのですか?
現在テキスト形式のデータに曲名を追加して読み込ませる方法も考えて
いるのですが・・・
できればフォルダの列挙をしてみたかったので><

non

Re:フォルダの読み込み

#5

投稿記事 by non » 16年前

すぐそばの「こ~ふぃ」さんのスレッド
「複数のtxtファイルやcsvファイルを比較したいのですが。」
と同じことを実現したいのでは?

Mist

Re:フォルダの読み込み

#6

投稿記事 by Mist » 16年前

> ちなみにDXライブラリとC言語だけでは実装は不可なのですか?
無理です。
DXライブラリはDirectXを簡易に使えるようにするためのライブラリですからフォルダに関する機能は対象外です。
また、フォルダの管理はOSに依存するところになりますのでC言語にはそのような関数はありません。

ポリ

Re:フォルダの読み込み

#7

投稿記事 by ポリ » 16年前

早い回答ありがとうございます。
やはりWinAPIを使わないとフォルダの列挙は無理ですか・・・
ゲームにコモンダイアログ等を出したくないので、
DXライブラリのFileRead等の関数を使ってテキストデータを一行ずつ
取り出してみようと思います。

回答してくださった皆様ありがとうございます。

non

Re:フォルダの読み込み

#8

投稿記事 by non » 16年前

_findfirstは環境には依存するけど(システムコール)
WindowsAPIではないと思ったんですが、違いますか?

Mist

Re:フォルダの読み込み

#9

投稿記事 by Mist » 16年前

_findfirstはCRTに含まれますのでWindowsAPIではないですね。
ポリさんの言うところのC言語を私は「ANSI C」と解釈しましたのでCRTは含んでいないです。

non

Re:フォルダの読み込み

#10

投稿記事 by non » 16年前

ポリさんが何をしたいのか、理解出来ていないし、DXライブラリも使ったことがないので
わからないのですが、環境に依存してはいけないのですか。
windowsでもUnixでもマックでも動くソフトを作りたいのでしょうか?

バグ

Re:フォルダの読み込み

#11

投稿記事 by バグ » 16年前

っていうか、DXライブラリを使っている時点でWindowsネイティブじゃないの?
WIN32API使うのは全然問題ないのではないかと思うんですけどねぇ?

Mist

Re:フォルダの読み込み

#12

投稿記事 by Mist » 16年前

ん~、私の回答悪かったでしょうか?

ポリさんはWinAPIはわかんないからDXライブラリ+C言語だけで出来ないかどうかを質問されていましたので「無理(だから勉強してね)」と回答しただけですけど。
環境依存は使いたくないとは一言も言っておられないですね。

> ゲームにコモンダイアログ等を出したくないので、
この回答から察するに、「WinAPIを使用する」=「何かダイアログが出る」と勘違いされているのかな?

non

Re:フォルダの読み込み

#13

投稿記事 by non » 16年前

>この回答から察するに、「WinAPIを使用する」=「何かダイアログが出る」と勘違いされているのかな?

よく読めば、コモンダイアログがどうとかって書いてありますね。
それなら、コモンダイアログは出ません。ってことでいいでしょうか。


_findfirstを使えば、フォルダの一覧も作れるし、再帰呼び出しにすれば
フォルダの中の子フォルダのファイル中身もすべて表示できます。

御津凪

Re:フォルダの読み込み

#14

投稿記事 by 御津凪 » 16年前

> _findfirstを使えば、フォルダの一覧も作れるし、再帰呼び出しにすれば
> フォルダの中の子フォルダのファイル中身もすべて表示できます。

こちらの方が32/64bit環境に対応している分、良いかもしれませんね。
WinAPI とほぼ同じ使い方ですし。

せっかくなので、_findfirst 関数使用バージョンを書いてみました。
WinAPI を使用しないため、日本語対応のための処理が入っています。
#include <io.h>
#include <tchar.h>

// WinAPI PathFindExtension 関数の代替
static _TCHAR* GetPathExtension( _TCHAR* path ){
    _TCHAR* i;
    if(!path) return NULL;
    for(i = path + _tcslen(path) - 1;i >= path;--i){
#ifdef _UNICODE
        // UNICODE 用処理
        if(*i == L'.'){
            break; // こっちだと簡単
        }
#else
        // ANSI(ShiftJIS) 用処理
        if(*i == '.'){
            _TCHAR c = *(i-1);
            if(*i == path || !((0x81 <= c && c <= 0x9F) || (0xE0 <= c && c <= 0xEF))){
                break; // こちらだと一つ前のバイト文字をチェックする必要がある
            }
        }
#endif
    }
    if(i < path) return path + _tcslen(path);
    return i;
}


// 検索処理関数
void SearchMP3File( const _TCHAR* str ){
    _finddata_t fd;
    intptr_t h = _tfindfirst(str,&fd);
    if(h == -1){ // パスが存在しない
        return;
    }
    do{
        if((fd.attrib & _A_SUBDIR) == 0 && // パスがフォルダでないもので、
            _tcsicmp(GetPathExtension(fd.name),_T(".mp3")) == 0) // 拡張子が".mp3"のファイル
        {
            _TCHAR buf[_MAX_PATH];
            // 検索ディレクトリパスとファイルパスを結合
            _tcscpy_s(buf,_MAX_PATH,str);
            _tcscat_s(buf,_MAX_PATH,_T('\\'));
            _tcscat_s(buf,_MAX_PATH,fd.name);
            // ここで buf には、MP3ファイルへのパスが入った状態。
            // 後は何らかの処理をここに入れる
        }
    }while(_findnext(h,&fd) == 0); // 次のパスを検索

    _findclose(h); // 検索ハンドルを閉じる
}
上記で書いた WinAPI 版と比べるとコードが若干増えていますが、
こちらの方が WinAPI を使用しない分、余計なものを定義されずにすみますね。

(これも上記で書いた環境と同じところで書いたので以下略。)

GPGA

Re:フォルダの読み込み

#15

投稿記事 by GPGA » 16年前

とっても手抜き
#include <stdio.h>
#include <iostream>
#include <string>
#include <vector>
#include <fstream>

/*!
 * @brief 指定したフォルダ内のmp3ファイル名をリストに出力
 *
 * @param outList 出力先を指定します。
 * @param directory ディレクトリを指定します。
 * @param tempListName 一時的なリストファイル名を指定します。
 *
 * @return true:正常終了 false:異常終了
 */
bool GetFileList(std::vector<std::string>& outList, const char* szDirectory, const char* tempListName)
{
	char s[256];
	sprintf(s, "dir /b %s\\*.mp3 > %s", szDirectory, tempListName);
	system(s);

	FILE* fp = fopen(tempListName, "r");
	while (fgets(s, sizeof(s), fp) != NULL) {
		s[strlen(s) - 1] = '\0';
		outList.push_back(s);
	}
	fclose(fp);

	sprintf(s, "del %s", tempListName);
	system(s);

	return true;
}
int main()
{
	std::vector<std::string> fileList;

	// カレントディレクトリを検索し、検索した結果を一時的にlist.txtに書き込む
	GetFileList(fileList, ".c", "list.txt");
	std::vector<std::string>::iterator it = fileList.begin();
	for (; it != fileList.end(); ++it) {
		std::cout << *it << std::endl;
	}
}
 

GPGA

Re:フォルダの読み込み

#16

投稿記事 by GPGA » 16年前

>御津凪さん

素朴なことなんですが、S-JISで '.'(0x2e) が2バイト目にくる2バイト文字って存在しなくないですか?
int main()
{
	unsigned char c = '.';
	for (unsigned char i = 0x81; i <= 0x9F; ++i) {
		printf("%c%c\n", i, c);
	}
	for (unsigned char i = 0xE0; i <= 0xEF; ++i) {
		printf("%c%c\n", i, c);
	}
	return 0;
}
 
Windows XP、VS2008にて確認

御津凪

Re:フォルダの読み込み

#17

投稿記事 by 御津凪 » 16年前

> 素朴なことなんですが、S-JISで '.'(0x2e) が2バイト目にくる2バイト文字って存在しなくないですか?

そういえばそうですね。
2バイト目判定無くても確かに正常に動作しますね。
// WinAPI PathFindExtension 関数の代替
static _TCHAR* GetPathExtension( _TCHAR* path ){
    _TCHAR* i;
    if(!path) return NULL;
    for(i = path + _tcslen(path) - 1;i >= path;--i){
        if(*i == _T('.')) return i;
    }
    return path + _tcslen(path);
}
判定を省いたもの&省コード化しておきます。

閉鎖

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