Excel (VBA)

Excel VBAに関するフォーラムです。
  • 掲示板への投稿には会員登録(無料)が必要です。会員登録がまだの方はこちら
  • 掲示板ご利用上のお願い」に反するご記入はご遠慮ください。
  • Q&A掲示板の使い方はこちらをご覧ください
トピックに返信
質問

 
(Windows 10全般 : Excel 2016)
VBAでのバイナリファイルの読み込みについて
投稿日時: 22/02/15 17:32:23
投稿者: mougmoug2

VBAでのバイナリファイルの読み込みが遅く、困っています。
 
現在、C言語で計算した結果データをバイナリファイルで出力し、
データの整理、グラフ出力のため、VBAでそのバイナリファイルを読み込んでいます。
 
例えば、int型でデータが格納されている場合、
@バイナリファイルのデータをGet関数でByte型の配列に格納。

AByte型の配列には、10進数で値が入っているため、16進数に戻す。

Bint型で格納されているため、4バイトごとに配列を分ける。

CRight関数かLeft関数で1バイトずつ読み込み、文字を連結する

DCLng("&H"& 文字列 )で10進数に変換
という手順でデータを読み込んでいます。
また、double型のデータの読み込みには規格に沿った変換があるため、さらに処理が増え読み込み時間が膨大になっています。
 
C言語では、fread関数で、データ型を指定すれば、@〜Dの処理を一括でやってくれるのですが、
VBAでもそういったバイナリを読み込む際に便利な関数はあるのでしょうか。
ご教授願います。

回答
投稿日時: 22/02/15 19:24:19
投稿者: QooApp

直接バイナリを高速で読む方法が思いつかなかったのですが、
 
▼下記のような高速読み込みに対応する形式でCから書き出したらいかがでしょうか。
http://officetanaka.net/excel/vba/speed/s15.htm

回答
投稿日時: 22/02/15 21:46:07
投稿者: よろずや

ユーザー定義型同士をLSET命令で転記すると自由に型変換できます。
 
Option Explicit
Type bttype
bt(3) As Byte
End Type
Type ittype
it As Long
End Type
Sub test()
Dim byt As bttype
byt.bt(0) = 1
byt.bt(1) = 2
byt.bt(2) = 3
byt.bt(3) = 4
Dim itt As ittype
LSet itt = byt
Debug.Print itt.it
End Sub
 

投稿日時: 22/02/16 09:38:38
投稿者: mougmoug2

QooApp様、回答ありがとうございます。
バイナリ形式ではなく、CSV形式で取り込む方法ですね。
試してみます。

投稿日時: 22/02/16 09:41:27
投稿者: mougmoug2

よろずや様、回答ありがとうございます。
ユーザー定義型同士で自由に型変換できるとは知りませんでした。
参考にさせていただきます。

回答
投稿日時: 22/02/19 21:39:59
投稿者: たらのり

こんばんは
  
日にちが空いてしまったので、もうご覧になっていないかしら……
  
次のように、バイナリファイルの内容を読み込むことができると思います。
  
Test1 は、Getステートメントで指定した変数の幅に合わせて、一つずつ
値を読み込みます。
Test2 は、レコード(構造体)を定義して、そのメンバに合わせて一括で
読み込みます。
  
使用する場面によっては、Type で指定する各メンバをオブジェクトの
大きさの整数倍のアドレスや、偶数アドレスに調整しなければならない
ことがあるかもしれませんが、読出しだけなら問題はなさそうな……。
この例では,わざと i32 のアドレスが奇数アドレスになるかもしれない
ように並べました(i8 に連接していれば,i32は奇数アドレスになるかも
しれないということです。込み入った話になるので詳細は割愛します)。
  
# VarPtr() でしたか,i32 のアドレスを調べてみればよかったです
  
  
リトルエンディアンなので、イミディエイトに印字される 16進数は
バイナリエディタで眺めたファイルの内容と逆転します。
ビッグエンディアンならバイトオーダーを逆転する必要があります。
 
  

Sub Test1() ' 一つずつ任意のサイズの整数を読み込む

    Const FILE_NAME = "C:\foo\bar\baz.bin"
    Dim fno As Integer
    
    Dim i8  As Byte     '  8ビット幅
    Dim i32 As Long     ' 32ビット幅
    Dim i16 As Integer  ' 32ビット幅
    
    
    fno = FreeFile()
    Open FILE_NAME For Binary Access Read As fno

    ' 逐次任意のバイト長の整数を読み込む
    Get #fno, , i8:     Debug.Print Hex(i8)
    Get #fno, , i32:    Debug.Print Hex(i32)    ' リトルエンディアン
    Get #fno, , i16:    Debug.Print Hex(i16)

    Close fno
    
End Sub

 
Private Type tRecord    ' レコード定義
    i8  As Byte         '  8ビット幅
    i32 As Long         ' 32ビット幅
    i16 As Integer      ' 16ビット幅
    
    ' …… to be continued
End Type

Sub Test2() ' 定義した構造体に合わせて一括読み込み

    Const FILE_NAME = "C:\foo\bar\baz.bin"
    Dim fno As Integer
    
    Dim t_  As tRecord
    
    fno = FreeFile()
    Open FILE_NAME For Binary Access Read As fno

    ' 構造体で一括に読み込む
    Get #fno, , t_
    
    Close fno
    
    Debug.Print Hex(t_.i8), Hex(t_.i32), Hex(t_.i16)
    
End Sub

  
# ご説明の内容のを曲解していたらスミマセン
  
 

トピックに返信