fc2ブログ
戯言徒然日記開発日記東方DTMC/C++DoJaLuaCG備忘録
気が向いたら創作活動とかしてる人のチラシの裏。
2007.07.17 Tue
ファイル名を表す文字列から「.(ドット)」を含む拡張子を取得する方法を紹介してみます。
もっとスマートな方法があればご教示願います(^^;)

<重要> コード内の一部の関数の使い方は非常に危険です!理解した上でご参照ください。
//------------------------------------------------------------------------------------------------
// 拡張子を取得するサンプルプログラム①
//------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>

int _tmain( void )
{
TCHAR filename[] = _T( "hogehoge.dummy" );
TCHAR extension[_MAX_PATH];

// 拡張子取得処理
TCHAR *temp = _tfullpath( NULL, filename, NULL ); // ①
_tsplitpath( temp, NULL, NULL, NULL, extension ); // ②
free( temp ); // ③

_tprintf_s( _T( "The Extension of \"%s\" is \"%s\"" ), filename, extension );

_tprintf_s( _T( "Please Hit Enter Key." ) );
getchar();

return 0;
}

では何をやっているのか順番に説明します。「拡張子取得処理」とコメントアウトしてる部分を見てみましょう。

    ①ファイル名を表す文字列からフルパスを作る
    ②フルパスをドライブ名、ディレクトリ名、ファイル名、拡張子に分割
    ③フルパス作成時の後片付け という処理を行っています。

次のようにマクロにして、

     #define FILE_GET_EXT(path,ext) { TCHAR *temp = _tfullpath( NULL, path, NULL ); _tsplitpath( temp, NULL, NULL, NULL, ext ); free( temp );}

FILE_GET_EXT( filename, extension );という感じで使ってます。

冒頭に挙げているように危険な箇所があります。コンパイル時に警告が出てるので気づくと思いますが_tsplitpath()です。
セキュリティ強化版の_tsplitpath_s()を使うといいのですが、セキュリティ強化版は引数にNULLを許さないようです。
よって、拡張子以外もすべて分割後に格納できるポインタを指定する必要があるみたいです。
//------------------------------------------------------------------------------------------------
// 拡張子を取得するサンプルプログラム②
//------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>

int _tmain( void )
{
TCHAR filename[] = _T( "hogehoge.dummy" );
TCHAR drive[_MAX_DRIVE];
TCHAR dir[_MAX_DIR];
TCHAR fname[_MAX_FNAME];
TCHAR extension[_MAX_PATH];

// 拡張子取得処理
TCHAR *temp = _tfullpath( NULL, filename, NULL );
_tsplitpath_s( temp, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME, extension, _MAX_EXT );
free( temp );

_tprintf_s( _T( "The Extension of \"%s\" is \"%s\"" ), filename, extension );

_tprintf_s( _T( "Please Hit Enter Key." ) );
getchar();

return 0;
}

赤字は追加部分です。個人的には①のサンプルコードでいいかなぁって思ってます。
拡張子取得のためにたくさん変数を作るのはちょっと・・・って感じなので。

問題点を挙げると、おそらくキリがないでしょう(笑)
あまり検証していないので、使っていく中でとんでもない目に遭いそうです(^_^;)
(そもそもフルパスを作る必要はあるのか…。 )


[追記]
フルパスを作らなくても_tsplitpath()にfilename入れても一応同じような結果が得られました。
が、リファレンスのパラメータには完全パスを入れるように書いてあるのでちょっと不安。
(そう思うならキチンと_tsplitpath_s()使えという話ですが…(^^;))

[修正]
 int main( void )をint _tmain( void )に修正しました。

[追記] 2007/07/26
ふと検索ワードを見てると PathFindExtension という関数があるようですね。
これを使うと、

    LPSTR extention = PathFindExtension( filename );

とするだけで拡張子を取得することができます。絶対パス・相対パス共に正常に動作しました。
ただし、

    #include <shlwapi.h>
    #pragma comment( lib, "shlwapi.lib" )

しておく必要があります。(Linkが面倒ですね(^_^;))

動作条件はInternet Exproler 4.0がインストールされているWindows 95以降でしょうか?
ANSI版およびUnicode版両方の実装がされているようです。
(当たり前ですがUnicodeバージョンはWindows 2000 以降ですね。)
管理者にだけ表示を許可する

TrackBackURL
→ http://niffy67.blog110.fc2.com/tb.php/2-b9b316d6
Template by まるぼろらいと