ファイルをバイナリ形式で表示する (C/C++編)
ディレクトリツリーの表示は CTreeViewクラス側で行いますので、アプリケーションとしてはツリーの各ノードにディレクトリ名を登録していくことになります。
以下の手順でディレクトリツリーに登録します。
ツリーのルートノード(最上位のノード)には、コンピュータ名を登録します。
コンピュータ名のすぐ下のノードには、接続されているドライブ名(ドライブレター)を登録します。
各ドライブ名の下のノードが、それぞれのドライブのディレクトリ構造をツリーで登録します。
GetComputerName()を呼び出してコンピュータ名を取得できたら、ツリーのルートノードとして登録します。
コンピュータ名が取得できない場合(多分ないのですが)、「My Computer」をルートノードとして登録します。
BOOL GetComputerName( LPTSTR lpBuffer, LPDWORD lpnSize );
引数 | 説明 |
---|---|
lpBuffer | コンピュータ名が格納されるバッファ。 |
lpnSize | lpBufferのバイト数。 |
ソースコード [FileTreeView.cpp]
/****************************************************************************/
/*!
* @brief コンピュータ名をツリーのルートノードにセットする.
*
* @param [in] treeCtrl ツリービューのオブジェクト.
*
* @retval 生成したルートノード.
*/
HTREEITEM CFileTreeView::AddRootNode( CTreeCtrl& treeCtrl )
{
//! コンピュータ名を取得する.
TCHAR buf[MAX_COMPUTERNAME_LENGTH+1] = {'\0'};
DWORD size = sizeof( buf ) / sizeof( TCHAR );
LPCTSTR ptr = buf;
if( !::GetComputerName( buf, &size ) ){
ptr = _T("My Computer");
}
//! コンピュータ名をツリーのルートノードにセットする.
HTREEITEM hRoot = treeCtrl.InsertItem( ptr, TVI_ROOT );
return hRoot;
}
GetLogicalDriveStrings()を呼び出してコンピュータに接続されている有効なドライブのドライブ名リストを取得します。
(ドライブ名リストを格納する領域の見積もりですが、1ドライブあたり「C:\」+ NULL文字の4文字必要で、最大で「A」~「Z」までの26個分確保するとして、 4 x 26 = 104 文字。これにリストの終端のNULL文字が必要だから、合計で105文字となります。105文字必要なのでキリのよいところで128文字確保しています。)
DWORD GetLogicalDriveStrings( DWORD nBufferLength, LPTSTR lpBuffer );
引数 | 説明 |
---|---|
nBufferLength | lpBufferのバッファサイズ。 |
lpBuffer | ドライブ名リストを格納するバッファのポインタ。 |
ドライブ名リストにはNULL文字終端されたドライブ名の文字列が順次格納されていて、リストの最後にNULL文字のみの文字列があります。
for()ループで回しながらドライブ名リストからドライブ名の文字列を取り出します。
取り出したドライブ名の最後にセパレータ文字「\」が付いているので、これを取り除いてツリーに登録します。
さらにドライブのルートディレクトリが存在する場合は、ドライブのノードに子ノードを追加してドライブのノードが展開できるようにします。
ソースコード [FileTreeView.cpp]
/****************************************************************************/
/*!
* @brief ディレクトリツリーにドライブ名を登録する.
*
* @param [in] treeCtrl ツリービューのオブジェクト.
* @param [in] hParent ドライブ名を登録するノード.
*
* @retval なし.
*/
void CFileTreeView::AddDriveName( CTreeCtrl& treeCtrl, HTREEITEM hParent )
{
//! 有効なドライブの文字列を取得する.
TCHAR buf[256] = {'\0'};
DWORD size = sizeof( buf ) / sizeof( TCHAR );
::GetLogicalDriveStrings( size, buf );
for( LPTSTR ptr = buf ; *ptr != _T('\0') ; ptr++ ){
//! ドライブ文字列からバックスラッシュ('\')を取り除く.
CString path = ptr;
path.Remove( _T('\\') );
//! ドライブをノードとしてツリーに登録する.
HTREEITEM hDrv = treeCtrl.InsertItem( path, hParent );
//! ドライブ名直下のディレクトリが存在するかを調べる.
AddDirectory( treeCtrl, hDrv, path, TRUE );
ptr += _tcslen( ptr );
}
}
FindFirstFile()とFindNextFile()を呼び出して、引数で指定されたディレクトリにあるファイル情報のリストを取得します。
HANDLE FindFirstFile( LPCTSTR lpFileName, LPWIN32_FIND_DATA lpFindFileData );
引数 | 説明 |
---|---|
lpFileName | ファイル名のポインタ。 |
lpFindFileData | 検索結果が格納されるファイル検索(WIN32_FIND_DATA)構造体のポインタ。 |
BOOL FindNextFile( HANDLE hFindFile, LPWIN32_FIND_DATA lpFindFileData );
引数 | 説明 |
---|---|
hFindFile | FindFirstFile()が返した検索ハンドル。 |
lpFindFileData | 検索結果が格納されるファイル検索(WIN32_FIND_DATA)構造体のポインタ。 |
リストの取得といっても一気に全ての情報が取得できるのではなく、FindFirstFile()で最初のファイル情報を取得したら、次のファイル情報はFindNextFile()を呼び出して1個づつ取り出すようになっています。
do~while()ループでFindNextFile()でファイル情報が取れなくなるまで処理します。
取得したファイル情報から次の条件が全て一致するファイルをツリーに登録します。
- ディレクトリである。
- 隠しファイルではない。
- カレントディレクトリ「.」ではない。
- 親ディレクトリ「..」ではない。
メソッドの呼び出しが「サブディレクトリの存在チェック」の場合(isDummyがTRUE)は、1個のディレクトリをツリーに登録した時点で処理は終了なのでループを抜けます。
展開→表示の場合は全てのディレクトリをツリーに登録するのでループを継続します。
展開→表示の場合、登録したディレクトリのノードが展開可能かどうかを設定する必要があるので、現在のディレクトリ名に登録したディレクトリ名を連結して、そのディレクトリにサブディレクトリがあるかどうかを調べます。
ソースコード [FileTreeView.cpp]
/****************************************************************************/
/*!
* @brief ディレクトリツリーにディレクトリ名を登録する.
*
* @param [in] treeCtrl ツリービューのオブジェクト.
* @param [in] hParent ディレクトリ名を登録するノード.
* @param [in] path 該当ノードに対応した絶対パスのディレクトリ名.
* @param [in] isDummy TRUE = サブディレクトリが存在するかどうかだけ調べる.
*
* @retval なし.
*/
void CFileTreeView::AddDirectory( CTreeCtrl& treeCtrl, HTREEITEM hParent, CString path, BOOL isDummy )
{
WIN32_FIND_DATA ffd;
memset( &ffd, 0, sizeof(WIN32_FIND_DATA) );
CString buf = path;
buf += _T("\\*.*");
//! 指定されたディレクトリ直下のファイルリストを取得する.
HANDLE sch = ::FindFirstFile( (LPCTSTR)buf, &ffd );
if( sch != INVALID_HANDLE_VALUE ){
/*!
* カレント・ディレクトリの下にあるディレクトリ名のみ抽出する.
* 但し、隠しディレクトリとカレント・ディレクトリ( "." ) はリストに含めない.
*/
do{
if( ( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
&& !( ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN )
&& ( _tcscmp( ffd.cFileName, _T(".") ) != 0 )
&& ( _tcscmp( ffd.cFileName, _T("..") ) != 0 )){
//! サブディレクトリを追加する.
HTREEITEM hItem = treeCtrl.InsertItem( ffd.cFileName, hParent );
//! サブディレクトリの存在チェックの場合は、1件検出した時点で処理を終了する.
if( isDummy ){
return;
}
//! サブディレクトリの存在チェックを行う.
CString newPath = path;
newPath += _T("\\");
newPath += ffd.cFileName;
AddDirectory( treeCtrl, hItem, newPath, TRUE );
}
memset( &ffd, 0, sizeof(WIN32_FIND_DATA) );
}while( ::FindNextFile( sch, &ffd ) ) ;
}
}
親ノードを再帰呼び出しで遡って、指定されたノードに対応したディレクトリの絶対パスを生成します。
ソースコード [FileTreeView.cpp]
/****************************************************************************/
/*!
* @brief 指定されたノードに該当するディレクトリの絶対パスを取得する.
*
* @param [in] treeCtrl ツリービューのオブジェクト.
* @param [in] hItem 親ディレクトリ.
*
* @retval なし.
*/
CString CFileTreeView::GetAbsolutePath( CTreeCtrl& treeCtrl, HTREEITEM hItem )
{
CString path = _T("");
//! 親ノードのハンドルを取得する.
HTREEITEM hParent = treeCtrl.GetParentItem( hItem );
/*!
* 親ノードが無い場合はルートノードなのでディレクトリ名は返さない.
* (ルートノードはコンピュータ名にしたから)
*/
if( !hParent ){
return path;
}
/*!
* 親ノードがあったので、親ノードまでのフルパスのディレクトリ名を
* 取得する.
*/
path = GetAbsolutePath( treeCtrl, hParent );
if( path.GetLength() > 0 ){
path += '\\';
}
//! 自ノードのディレクトリ名を取得して、親ノードのディレクトリ名と連結する.
CString name = treeCtrl.GetItemText( hItem );
path += name;
return path;
}
親ノードのハンドルを取得するにはCTreeCtrlのGetParentItem()メソッドを呼び出します。
HTREEITEM CTreeCtrl::GetParentItem( HTREEITEM hItem ) const;
引数 | 説明 |
---|---|
hItem | 親ツリーのハンドルを取り出すノードのハンドル。 |
戻り値 | 親ツリーのハンドル。 |
ノードに表示しているディレクト名を取得するにはCTreeCtrlのGetItemText()メソッドを呼び出します。
CString CTreeCtrl::GetItemText( HTREEITEM hItem ) const;
引数 | 説明 |
---|---|
hItem | ノードに表示しているテキストを取り出すノードのハンドル。 |
戻り値 | ノードに表示しているテキスト。 |