プログラム講座 中級編26

- バイナリーデータをテキスト(数値)データに変換する -

 中級編26です。今回は「バイナリーデータをテキスト(数値)データに変換する」アプリを作ります。今までの講座ででてきたプログラムを流用しているだけです。ドラッグドロップも可能となっています。




バイナリデータとテキストデータ
 バイナリデータとテキストデータ、どこが違うのでしょうか? テキストデータは基本的にアスキーコード文字(2バイトコード含む)で構成されており、テキストエディタ等で読む(見る)事ができます。これに対しバイナリデータは0〜255の数値で構成されています。つまりどんな数値を使用しても構いません。バイナリデータをテキストエディタ等で強引に開く(注意)と、わけのわからない文字や記号が表示されます。

 今回はバイナリデータ(1バイトのデータ)を読み込んでエクセル等で読み込める「カンマ区切りテキスト」の形式に変換してみます。と言っても、難しい事は何もありません。


注意
ResEditなどでファイルタイプをTEXTに変える必要があります。



バイナリーデータからテキストデータへの変換
 まず、バイナリーデータをメモリに読み込みます。ファイルから1バイトづつ読み込んでも構いません。読み込まれた変数名をcode%とします。

ファイルから直接読み込むメモリから読み込む
READ #1ファイル番号,code$;1
code% = ASC(code$)
code% = PEEK(address&)

 読み込まれたデータを以下のようにしてファイルに書き出せばおしまいです。

PRINT #1,code%

 


8個ごとに改行する
 このままだと、生成されたデータをEXCEL等で読み込ませると縦に長くつづくデータとなってしまいます。とりあえず。8個ごとに改行しましょう。
 まず、カウンタを用意します。このカウンタをwcount%とします。カウンタに1を加算し8になったら改行するという処理を行います。

wcount% = wcount% + 1
if wcount% = 8 then wcount% = 0


 通常はこのようにIF文を使って記述しますが、今回は「論理演算」を使っています。論理演算を使った場合、以下のようになります。

wcount % = ( wcount% + 1 ) AND 7

 AND命令が論理演算を行うものです。AND命令は2つの数のビットが1の場合のみ1を返す、という特徴を持っています。上記の命令を回数に従って表にしてみるとよくわかるでしょう。なお、[ ]内の数値は2進数で表しています。

回数wcount%の値論理積を取る値演算結果
00 [0000]7 [0111]0 [0000]
11 [0001]7 [0111]1 [0001]
22 [0010]7 [0111]2 [0010]
33 [0011]7 [0111]3 [0011]
44 [0100]7 [0111]4 [0100]
55 [0101]7 [0111]5 [0101]
66 [0110]7 [0111]6 [0110]
77 [0111]7 [0111]7 [0111]
80 [0000]7 [0111]0 [0000]
91 [0001]7 [0111]1 [0001]
102 [0010]7 [0111]2 [0010]
113 [0011]7 [0111]3 [0011]

 このように下の3つのビットのみ変化しその他のビットは変化しません。つまり絶対に0〜7までの値にしかならないというわけです。

 このような方法はゲーム等でよく見られます。キャラクタがアニメーションするような場合でも、2のn乗になるようにキャラクタパターンを作ります。例えば人が歩くような場合、4パターンの画像を用意します。現在のアニメーションパターン番号を示す変数をanime%とすると、

anime% = ( anime% + 1 ) AND 3

 といった具合に非常にシンプルかつ高速に処理できます。ゲームを作る人や高速化をはかりたい人は覚えておくと良いでしょう。特にFuture BASICでは有効な手段です。



終わりに
 論理演算について説明していないのに気づきました(^^; 今回は手はじめという事で、別の機会に論理演算のみについて説明したいと思います。



今回のプログラムリスト
'--------------------------------------------------------------------- ' "バイナリーデータをEXCELで読める「カンマ区切りテキスト」に変換します" '--------------------------------------------------------------------- OUTPUT FILE "BINtoASC": ' "作成するアプリケーション名の指定" RESOURCES "BINtoASC.res" _memoryError = 257: ' "メモリ不足のアラート" gQuit_flag = _false: '"終了フラグ" END GLOBALS '--------------------------------------------------------------------- ' "バイナリーデータからテキストに変換する" '--------------------------------------------------------------------- LOCAL FN BINtoASC(openfile$,openRefNum%) LONG IF openfile$ = "" openfile$ = FILES$(_fOpen,"",,openRefNum%): ' "ファイル選択ダイアログの表示" END IF LONG IF openfile$<>"" savefile$ = FILES$(_fSave,"ファイル名","",saveRefNum%):' "ファイル保存ダイアログの表示" LONG IF savefile$<>"" DEF OPEN "TEXTttxt": ' "TeachText/SimpleText形式で保存" OPEN "I",#1,openfile$,,openRefNum%: ' "変換元のファイルをオープン" fileSize& = LOF(1,1): ' "ファイルサイズを求める" myHandle& = FN NEWHANDLE(fileSize&): ' "ファイルサイズ分メモリを確保します!" convHandle& = FN NEWHANDLE(fileSize&*2): ' "変換サイズ分メモリを確保します!" count& = 0: ' "書き出すバイト数をクリア" LONG IF myHandle& = 0 OR convHandle& = 0: ' "ハンドルサイズが0の時はメモリ不足で確保できなかった!" CALL PARAMTEXT("メモリ不足で変換できませんf(-.-b","","","") err% = FN ALERT(_memoryError,0): ' "ファイルサイズが巨大なため読み込むことが出来ません" XELSE err% = FN HLOCK(myHandle&): ' "メモリが移動しないようにハンドルをロック" err% = FN HLOCK(convHandle&): ' "メモリが移動しないようにハンドルをロック" READ FILE #1,[myHandle&],fileSize&: ' "ファイルを読み込む" CLOSE #1 OPEN "O",#1,savefile$,,saveRefNum%: ' "変換先のファイルをオープン" pointer& = [convHandle&]: ' "ポインタを求める" wcount% = 0 FOR i& = 0 TO fileSize&-1: ' "ファイルサイズ分繰り返す" code% = PEEK([myHandle&] + i&): ' "1バイト読み込む" INC(wcount%) wcount% = wcount% AND 7 IF wcount% > 0 THEN PRINT #1,code%;","; ELSE PRINT #1,code% NEXT CLOSE #1 END IF DEF DISPOSEH(myHandle&): ' "確保したメモリを解放する" DEF DISPOSEH(convHandle&): ' "確保したメモリを解放する" END IF END IF END FN '--------------------------------------------------------------------- ' "メニューの初期化:アバウト画面は手抜きのためなしf(^^b" '--------------------------------------------------------------------- LOCAL FN initMenu MENU 1,0,_enable,"ファイル" MENU 1,1,_enable,"/O変換..." MENU 1,2,_disable,";" MENU 1,3,_enable,"/Q終了" END FN '--------------------------------------------------------------------- ' "選択されたメニューに応じて処理を振り分けます" '--------------------------------------------------------------------- LOCAL FN doMenu menuID = MENU(_menuID): '"メニューバーのどの項目かな?" itemID = MENU(_itemID): '"プルダウンメニューのどの項目かな?" SELECT menuID: '"まずは、どのメニューバーか調べます" CASE 1 SELECT itemID CASE 1 FN BINtoASC("",0) CASE 3 gQuit_flag = _true: '"終了スイッチオン" END SELECT END SELECT MENU: '"メニューのハイライトを戻します" END FN '--------------------------------------------------------------------- ' "ドラッグされたファイルを調べます" '--------------------------------------------------------------------- LOCAL FN dragDrop maxFile% = 1 theType = FINDERINFO(maxFile%,filename$,fileType&,vRefNum%) IF maxFile% THEN FN BINtoASC(filename$,vRefNum%) END FN '--------------------------------------------------------------------- ' "メインルーチン、イベントループ処理(自動)" '--------------------------------------------------------------------- WINDOW OFF: '"起動時にウィンドウを表示しないように指定" FN initMenu: '"メニューの構築" ON MENU FN doMenu: '"メニューイベントが発生したときの飛び先" FN dragDrop DO HANDLEEVENTS: '"イベントループ" UNTIL gQuit_flag