ファイルをバイナリ形式で表示する

概要

サンプルコードは読めるけど、実際のプログラムは書けないという方を対象に小規模なプログラムの作り方を解説してみようと思います。

第一弾として、ハードディスクの内容を各ディレクトリ毎に一覧表示して、選択したファイルの内容を16進数のバイナリ形式で表示するプログラムです。

何かの役に立つプログラムかと言うと、たいして役には立ちません。(まぁ、学習用なので。)

使用する言語はC/C++、C#、VB、Javaのそれぞれで作りますので、わかる言語のプログラムを参考にしてください。

プログラムの仕様

作成するプログラムは以下の仕様にします。

  • ウインドウ・スタイルは3ペインの分割ウインドウとし、ディレクトリのツリー表示、ディレクトリ内のファイル一覧表示、および、バイナリ形式のファイルの内容表示とします。

  • ディレクトリツリーはルートを「コンピュータ名」とし、その直下に各ドライブのディレクトリ構成をツリー表示します。

  • ディレクトリツリーはディレクトリのみの表示とし、ファイル名は表示しません。

  • ディレクトリツリーには隠しディレクトリは表示しません。

  • ディレクトリツリーで選択されたディレクトリの内容をファイルの一覧表示ウインドウに表示します。

  • ファイル一覧には該当するディレクトリに含まれるディレクトリ名とファイル名を表示します。

  • ファイル一覧には隠しディレクトリと隠しファイルは表示しません。

  • ファイル一覧でディレクトリ名をダブルクリックされた場合はクリックされたディレクトリに移動して、移動したディレクトリの内容を一覧表示します。

  • ファイル一覧でファイル名をダブルクリックされた場合はクリックされたファイルの内容をバイナリ形式で表示します。

  • ファイル一覧でディレクトリ移動したとしてもバイナリ形式で表示中の内容は更新しません。

  • バイナリ形式でのファイル表示では1行に16バイト表示し、1行に16進数の表示に続いてASCIIコードでも表示します。

  • ASCIIコードでの表示は20H~7FHまでとし、その他のコードは「.」で表示することにします。
    (漢字コードの表示は行いません。)


サンプルプログラムの外観は以下のようにします。

プログラムの機能設計

最初にプログラムの構成を考えます。

今回、作成するプログラムでは画面の表示以外の機能がないので、プログラムは大きく分けて以下の3つの機能になります。

  • ディレクトリのツリー表示。
  • ファイルの一覧表示。
  • ファイルの内容をバイナリ形式で表示。

次にそれぞれの画面の操作からの処理の流れを考えます。

ディレクトリツリーでは以下の操作があります。

  • ディレクトリのノードを開く。
    →表示はコントロールで行いますが、表示するディレクトリ名の追加はアプリケーション側で行います。

  • ディレクトリのノードを閉じる。
    →操作としてはあるのですが、今回は何も実装しません。

  • ディレクトリのノードを選択する。
    →選択したノードのディレクトリ名をファイル一覧画面に通知してファイル一覧の表示を更新します。


ファイル一覧画面では以下の操作があります。

  • 表示中のファイルリストからディレクトリを選択する。
    →選択したディレクトリ名をディレクトリツリーに通知してツリーの選択中ノードの表示を更新します。

  • 表示中のファイルリストからファイルを選択する。
    →選択したファイル名をバイナリ表示画面に通知して選択したファイルの内容をバイナリ表示します。


バイナリ表示画面では以下の操作があります。

  • ファイルの内容をバイナリ形式で描画。
    →テキストボックス等のコントロールを使用しないで自前でテキストの描画を行います。

  • スクロールバーの操作。
    →自前でテキストの描画を行いますので、スクロールバーの操作も自前で行います。


各画面間の情報の通知は図のようになります。

ディレクトリツリー

ディレクトリツリーで実装する機能は以下のようになります。

  • アプリケーションが起動されたときにディレクトリツリーを画面に表示します。

  • ディレクトリツリーの特定ノードを展開するときに、サブディレクトリのノードを展開するノードの子ノードとして追加します。

  • ディレクトリツリーの特定のノードをクリックしたときに、ファイル一覧画面でクリックしたノードに対応したディレクトリのファイルリストを画面に表示します。


ディレクトリツリーの表示

ディレクトリのツリー表示にはツリーコントロールを使用します。

ツリー画面の表示自体はツリーコントロールが行いますので、アプリケーションとしては各ディレクトリに対応するノードをツリーコントロールに追加していく作業を行います。

ツリーコントロールへのディレクトリの追加ですが、ツリーコントロールの初期化時に全てのディレクトリを読み込むと時間がかかるので、ツリーの各ノードが展開されるときに該当するディレクトリにあるサブディレクトリのみを読み込んでツリーコントロールにセットしていく方法にします。

ツリーコントロールが生成されるタイミングで、ツリーの最上位のノード(ルートノード)に「コンピュータ名」をセットします。

次にルートノードの直下にコンピュータに接続されているストレージのドライブレターをルートノードの子ノードとしてセットします。


ディレクトリのノードを開く

ディレクトリツリーの特定のノードを開くと、ノードの展開イベントが発生します。

ノードの展開イベントでは、開こうとしたノードに対応したディレクトリのファイル一覧を取得し、ファイルの属性がディレクトリのファイルのみを子ノードとして追加します。
(このとき隠しディレクトリも除外します。)

追加した子ノードに対応したディレクトリにサブディレクトリがある場合、このままでは展開できるノードとならないので、追加した子ノードの下に孫ノードを追加してあげます。

但し、このときは全てのサブディレクトリ分のノードを追加する必要はないので1個だけ追加します。
(この子ノードが展開されるときに改めて全てのサブディレクトリが追加されるので。。。)


ディレクトリのノードを選択する

ディレクトリツリーの特定のノードをクリックすると、ノードの選択イベントが発生します。

各ノードに該当するディレクトリの絶対パス名はデータとしては持っていないので、選択されたノードを元に絶対パス名を生成します。

指定されたノードの絶対パス名は、

「親ノードの絶対パス名」+「区切り文字(\)」+「指定されたノードのディレクトリ名」

となりますので、親ノードを辿ってルートノードまで遡って、「親ノードの絶対パス名」+「ディレクトリ名」を指定されたノードまで繰り返せばディレクトリの絶対パスが取得できます。


最後に取得したディレクトリの絶対パスをファイル一覧画面に通知します。

ディレクトリツリー側の作業はこれでおしまいです。

実際のファイル一覧の取得および表示はファイル一覧画面側が行います。

ファイルの一覧表示

ファイル一覧画面では、一覧表示するディレクトリが通知されてきたときに、指定されたディレクトリのファイル一覧を取得して、ディレクトリ→ファイルの順に並べて表示します。
(通知されたディレクトリの絶対パス名は、後で使用するのでメンバ変数等にコピーしてとっておきます。)

ファイル一覧に表示しているファイル名をダブルクリックしたときに、クリックされたファイル名がディレクトリかファイルかで以下のように処理が別れます。

クリックされたファイル名がディレクトリの場合。

現在表示しているディレクトリの絶対パスにクリックされたファイル名を連結して次に移動するディレクトリの絶対パスとして、ディレクトリツリーに通知します。


クリックされたファイル名がファイルの場合。

現在表示しているディレクトリの絶対パスにクリックされたファイル名を連結してファイルの内容を表示するファイルとして、バイナリ表示画面に通知します。
このとき、併せてステータスバーにもファイル名を通知します。

ファイルの内容をバイナリ形式で表示

ファイルデータを16進数形式で表示する画面ですが、読み込むファイルサイズの上限を10Mバイトに制限しても、1行当たりに16バイトしか表示出来ない為、必要な最大行数は

(1024 x 1024 x 10) / 16 = 655360 行

となり、これをテキストボックス等のコントロールを使用して表示するには少し大きいので、ピクチャコントロール等を使用して、グラフィックのテキスト描画で画面に見えている行のデータだけ描画するようにします。


表示する文字位置を揃える為に、テキスト描画で使用するフォントは固定幅フォントにします。


表示を見やすくする為に1行のバイナリデータに対して「+0」~「+F」のスケールを表示するようにします。
また、各行に対応したファイルのオフセットアドレスも表示するようにします。


画面に描画する行位置は、垂直スクロールバーのつまみの位置となります。
最大行数が 655360行 + α となりますが、今回はどのフレームワークでも設定可能な最大数は必要な最大行数よりも大きいので、スクロールバーのつまみの位置をそのまま 1:1 で使用し、画面の1行目に表示するオフセットアドレスは

(オフセットアドレス) = (垂直スクロールバーのつまみの位置) × 16

と、なります。


表示されていない行を表示する為のユーザーインターフェースとしてスクロールバーが必要になるのですが、ピクチャコントロール等に準備されているスクロールバーは画面からはみ出しているピクチャのビットマップをスクロールで見えるようにする為のスクロールバーなので、今回のようにピクチャ自体からはみ出すデータを表示する為のスクロールとはスクロールできる範囲が全然違ってしまいます。



今回はピクチャコントロール等に用意されているスクロールバーは使用しないで、外付けのスクロールバーでスクロールする領域を管理するようにします。


以上で今回作成するプログラムの機能設計が出来ましたので、いよいよコーディングをしていきます。



商標に関する表示