ファイルをバイナリ形式で表示する (C#/VB Winow Form編)
ファイル一覧で表示中のファイル名またはディレクトリ名をダブルクリックしたときに、クリックしたのがファイル名であれば、現在表示中のファイルデータの内容をクリックされたファイル名のデータに更新します。
クリックされたのがディレクトリ名であればファイル一覧の表示をクリックされたディレクトリの一覧に更新します。
処理の流れは以下のようになります。
リストビューをダブルクリックしたときのイベントハンドラ
ディレクトリ名をダブルクリックした場合
ディレクトリツリーの選択ノードを変更する
ファイル一覧の表示を変更する
ファイル名をダブルクリックした場合
ファイルを読み込む
ファイルデータの表示を変更する
リストビューの項目をダブルクリックしたときのイベントハンドラ
リストビューの項目をダブルクリックしたときのイベント処理を行います。
リストビューの項目をダブルクリックしたときのイベント処理を行うために、DoubleClick()メソッドをオーバーライドします。
「FileList」の「DoubleClick」プロパティに「FileList_DoubleClick」を追加します。
C# ソースコード [FileListView.cs]
// -----------------------------------------------------------------------
/// <summary>
/// ファイル一覧の項目がダブルクリックされたときの操作イベント.
/// </summary>
/// <param name="sender">
/// イベントを発生させたオブジェクト.
/// </param>
/// <param name="e">
/// イベント・パラメータ.
/// </param>
private void FileList_DoubleClick( object sender, EventArgs e )
{
if( FileList.SelectedItems.Count > 0 ){
/*!
* リストビューからファイル名を取り出して、カレントディレクトリ名と連結して
* 選択されたファイルの絶対パスにする.
*/
string filename = FileList.SelectedItems[0].Text;
string fullpath;
if( CurrentDir.Length > 0 ){
fullpath = CurrentDir + "\\" + filename;
}else{
fullpath = filename;
}
//! ".."の場合、カレントパスの最後のディレクトリ名を取り除く.
if( filename.Equals( ".." ) ){
int pos = CurrentDir.LastIndexOf( '\\' );
if( pos >= 0 ){
fullpath = CurrentDir.Substring( 0, pos );
}else{
ExpandDirectory( "" );
return;
}
}
var attr = File.GetAttributes( fullpath );
if( (attr & FileAttributes.Directory) == FileAttributes.Directory ){
//! 選択されたファイルがディレクトリの場合、選択されたディレクトリに移動する.
ExpandDirectory( fullpath );
}else{
//! ファイルを読み込む.
FileBuff = ReadFile( fullpath );
//! ステータスバーにファイル名を表示する.
StatusLabel1.Text = fullpath;
//! 読み込んだファイルの内容を表示する.
ShowFile();
}
}
}
VB ソースコード [FileListView.vb]
'' -----------------------------------------------------------------------
''' <summary>
''' ファイル一覧の項目がダブルクリックされたときの操作イベント.
''' </summary>
''' <param name="sender">
''' イベント対象のオブジェクト.
''' </param>
''' <param name="e">
''' イベントパラメータ.
''' </param>
Private Sub FileList_DoubleClick( sender As Object, e As EventArgs ) Handles FileList.DoubleClick
If FileList.SelectedItems.Count > 0 Then
' リストビューからファイル名を取り出して、カレントディレクトリ名と連結して
' 選択されたファイルの絶対パスにする.
Dim filename As String = FileList.SelectedItems(0).Text
Dim fullpath As String
If CurrentDir.Length > 0 Then
fullpath = CurrentDir + "\" + filename
Else
fullpath = filename
End If
' ".."の場合、カレントパスの最後のディレクトリ名を取り除く.
If filename.Equals( ".." ) Then
Dim pos As Integer = CurrentDir.LastIndexOf( "\" )
If pos >= 0 Then
fullpath = CurrentDir.Substring( 0, pos )
Else
ExpandDirectory( "" )
Return
End If
End If
Dim attr As System.IO.FileAttributes = System.IO.File.GetAttributes(fullpath)
If (attr And System.IO.FileAttributes.Directory) = System.IO.FileAttributes.Directory Then
' 選択されたファイルがディレクトリの場合、選択されたディレクトリに移動する.
ExpandDirectory( fullpath )
Else
' ファイルを読み込む.
FileBuff = ReadFile( fullpath )
' ステータスバーにファイル名を表示する.
StatusLabel1.Text = fullpath
' 読み込んだファイルの内容を表示する.
ShowFile()
End If
End If
End Sub
リストビューから選択された項目のファイル名を取り出して、現在表示中のディレクトリ名と連結して選択されたファイルの絶対パスを作ります。
ファイル名が「..」の場合、1つ上の階層にディレクトリとなるので、現在表示中のディレクトリの絶対パスから最後のディレクトリ名を取り除いて移動するディレクトリの絶対パス名にします。
ダブルクリックされたファイル名が「ディレクトリ」の場合、ディレクトリの移動を通知します。
ダブルクリックされたファイル名が「ファイル」の場合、以下の処理を行います。
データ表示するファイルを読み込みます。
ステータスバーに表示するファイル名を通知します。
ファイルデータ表示ビューを表示します。
指定されたディレクトリまでのノードを展開して該当ノードを選択状態にします。
C# ソースコード [FileTreeView.cs]
// -----------------------------------------------------------------------
/// <summary>
/// 指定されたディレクトリのノードを選択状態にする.
/// </summary>
/// <param name="path">
/// 選択するディレクトリの絶対パス名.
/// </param>
private void ExpandAndSelectDirectory( string path )
{
TreeNode node = FileTree.Nodes[0];
//! IndexOf()検索で最後まで検索するようにパスの最後に検索文字を付加する.
string wkPath = path + "\\";
int nextPos;
int nowPos = 0;
while( node != null ){
//! ディレクトリ名を取り出す.
nextPos = wkPath.IndexOf( '\\', nowPos );
if( nextPos < 0 ){
break;
}
//! 子ノードが無い場合は処理を終了する.
if( node.Nodes.Count == 0 ){
node = null;
break;
}
//! "\"が連続している場合は読み飛ばす.
if( nextPos == nowPos ){
nowPos = nextPos + 1;
continue;
}
//! ディレクトリ名を絶対パスから取り出す.
string dirName = wkPath.Substring( nowPos, (nextPos - nowPos) );
nowPos = nextPos + 1;
foreach( TreeNode wkNode in node.Nodes ){
//! 同じディレクトリ名のノードを見つけたらループを抜ける.
if( dirName.Equals( wkNode.Text, StringComparison.OrdinalIgnoreCase ) ){
if( !wkNode.IsExpanded ){
wkNode.Expand();
}
node = wkNode;
break;
}
}
}
//! ノードを選択状態にする.
if( node != null ){
FileTree.SelectedNode = node;
FileTree.Focus();
}
}
VB ソースコード [FileTreeView.vb]
'' -----------------------------------------------------------------------
''' <summary>
''' 指定されたディレクトリのノードを選択状態にする.
''' </summary>
''' <param name="path">
''' 選択するディレクトリの絶対パス名.
''' </param>
Private Sub ExpandAndSelectDirectory( path As String )
Dim node As TreeNode = FileTree.Nodes(0)
' IndexOf()検索で最後まで検索するようにパスの最後に検索文字を付加する.
Dim wkPath As String = path + "\"
Dim nextPos As Integer
Dim nowPos As Integer = 0
While Not node Is Nothing
' ディレクトリ名を取り出す.
nextPos = wkPath.IndexOf( "\", nowPos )
If nextPos < 0 Then
Exit While
End If
' 子ノードが無い場合は処理を終了する.
If node.Nodes.Count = 0 Then
node = Nothing
Exit While
End If
' "\"が連続している場合は読み飛ばす.
If nextPos = nowPos Then
nowPos = nextPos + 1
Continue While
End If
' ディレクトリ名を絶対パスから取り出す.
Dim dirName As String = wkPath.Substring( nowPos, (nextPos - nowPos) )
nowPos = nextPos + 1
For Each wkNode As TreeNode In node.Nodes
' 同じディレクトリ名のノードを見つけたらループを抜ける.
If dirName.Equals( wkNode.Text, StringComparison.OrdinalIgnoreCase ) Then
If Not wkNode.IsExpanded Then
wkNode.Expand()
End If
node = wkNode
Exit For
End If
Next
End While
' ノードを選択状態にする.
If Not node Is Nothing Then
FileTree.SelectedNode = node
FileTree.Focus()
End If
End Sub
指定された絶対パスのディレクトリ名から、各ディレクトリ名を取り出す為にstring.IndexOf()メソッドでセパレータ「\」で区切って取り出すのですが、指定された絶対パスのディレクトリ名は最後にセパレータ文字が付いていないので、「\」を絶対パスの最後に付加します。
ルートノードから子ノードのディレクトリ名と指定された絶対パスのディレクトリ名から取り出したディレクトリ名を比較して、一致した子ノードから孫ノードのディレクトリ名と指定された絶対パスのディレクトリ名から取り出した次のディレクトリ名を比較して、一致したら....
という具合に指定された絶対パスのディレクトリ名が無くなるまで繰り返します。
このとき一致したノードが展開していなかった場合は展開します。
(これ表示上の問題もありますが、ノードを展開しないとサブディレクトリのリストが子ノードに反映されないので探索がここで終わってしまいます。)
最後まで探索して見つかったノードを選択状態にします。
(ついでにツリービューにフォーカスを移します。)
表示するファイルデータを読み込みます。
C# ソースコード [FileListView.cs]
// -----------------------------------------------------------------------
/// <summary>
/// ファイルを読み込む.
/// </summary>
/// <param name="path">
/// 読み込むファイル名.
/// </param>
/// <returns>
/// 読み込んだファイル・データを格納したバイト配列.
/// </returns>
private byte[] ReadFile( string path )
{
//! ファイルを読み込みモードでオープンする.
using( var fs = new FileStream( path, FileMode.Open, FileAccess.Read ) ){
//! ファイルのバイト数を取得する.
var size = fs.Length;
/*!
* ファイルサイズが読み込みサイズの上限を超える場合は
* サイズの上限までしか読み込まない.
*/
if( size > MaxFileSize ){
size = MaxFileSize;
}
//! ファイルサイズ分のファイルの読み込み用バッファを確保する.
var buf = new byte[size];
//! ファイルを読み込み用バッファに1回で読み込む.
fs.Read( buf, 0, buf.Length );
return buf;
}
}
VB ソースコード [FileListView.vb]
'' -----------------------------------------------------------------------
''' <summary>
''' ファイルを読み込む.
''' </summary>
''' <param name="path">
''' 読み込むファイル名.
''' </param>
''' <returns>
''' 読み込んだファイル・データを格納したバイト配列.
''' </returns>
Private Function ReadFile( path As String ) As Byte()
' ファイルを読み込みモードでオープンする.
Using fs As New System.IO.FileStream( path, System.IO.FileMode.Open, System.IO.FileAccess.Read )
' ファイルのバイト数を取得する.
Dim size As Integer = fs.Length
' ファイルサイズが読み込みサイズの上限を超える場合は
' サイズの上限までしか読み込まない.
If size > MaxFileSize Then
size = MaxFileSize
End If
' 割り当てられる要素数はインデックス(size) +1となるので -1して確保する.
Dim buf(size - 1) As Byte
' ファイルを読み込み用バッファに1回で読み込む.
fs.Read(buf, 0, buf.Length)
Return buf
End Using
End Function
ファイルを読み込みモードでオープンします。
ファイルサイズを取得します。
ファイルサイズが読み込み上限(10MB)を超えていた場合は読み込むサイズを読み込み上限値にします。
ファイルの読み込み用バッファを確保します。
確保した読み込み用バッファにファイルの内容を読み込みます。
(読み込むデータサイズ分のメモリは確保してあるので一気に読み込みます。)
usingで囲ってあるので、usingを抜けるときにファイルは自動でクローズされます。
読み込んだファイルの内容を表示します。
スクロールバーを初期化します。
画面に合わせてスクロールバーのつまみ位置の長さを設定します。
ファイルデータ表示ビューを再描画します。
C# ソースコード [FileDataView.cs]
// -----------------------------------------------------------------------
///
/// ファイルの内容を表示する.
///
private void ShowFile()
{
//! 垂直スクロールバーを初期化する.
FileDataVScroll.Value = 0;
FileDataVScroll.Minimum = 0;
FileDataVScroll.Maximum = (FileBuff.Length / 16);
//! 水平スクロールバーを初期化する.
FileDataHScroll.Value = 0;
FileDataHScroll.Minimum = 0;
FileDataHScroll.Maximum = 74;
//! 画面に合わせてスクロールバーのつまみ幅を設定する.
SetScrollBar();
//! バイナリ表示画面を再描画する.
splitContainer2.Panel2.Refresh();
}
VB ソースコード [FileDataView.vb]
'' -----------------------------------------------------------------------
'''
''' ファイルの内容を表示する.
'''
Private Sub ShowFile()
' 垂直スクロールバーを初期化する.
FileDataHScroll.Value = 0
FileDataVScroll.Value = 0
FileDataVScroll.Maximum = (FileBuff.Length / 16)
' 水平スクロールバーを初期化する.
FileDataHScroll.Value = 0
FileDataHScroll.Minimum = 0
FileDataHScroll.Maximum = 74
' 画面に合わせてスクロールバーのつまみ幅を設定する.
SetScrollBar()
' バイナリ表示画面を再描画する.
SplitContainer2.Panel2.Refresh()
End Sub