DOBON.NET DOBON.NETプログラミング掲示板過去ログ

バイナリーファイルから構造体へのセット方法

環境/言語:[VB.NET 2010]
分類:[.NET]

バイナリーファイルから構造体にデータをセットする処理を
下記の様にしています。これは成功しています。

Public Structure DATA
  Public cd as Integer
  Public name as String
End Structure


Public Function MainSyori() As DATA
  Dim n as Integer = FreeFile()
  Dim path as String = "c:\果物.dat"  'バイナリーファイル
  Dim data_wk as DATA

  'バイナリーファイルから、構造体へセット
  FileOpen(n, path, OpenMode.Binary, OpenAccess.Read,OpenShare.LockWrite)
  FileGet(n, data_wk)
  FileClose(n)

  MainSyori = data_wk

End Fucntion



果物.datのバイナリーファイルをリソース化して

(※My Project → リソース → リソースの追加 → 
  既存ファイルの追加 →バイナリーファイルを指定)

リソースから構造体にセットする様に変更したいのです。


下記の様な感じ出来るといいのですが何か良い方法はないでしょうか。

これはDirectCastの所でエラーになります。

Public Function MainSyori() As DATA
  Dim data_byte As Byte()

  data_byte = My.Resources.果物

  MainSyori = DirectCast(data_byte, DATA)

End Function


よろしくお願いします。
■No32581に返信(ひろこさんの記事)
> バイナリーファイルから構造体にデータをセットする処理を
> 下記の様にしています。これは成功しています。

レガシーの FileOpen は、ファイルからの入出力しか行えません。

そのため、FileOpen を使って読み出すのであれば、一時フォルダ等に
そのリソース内容をコピーし、そこから読み直すという手順が必要になります。


メモリ上から直接読み取りたいのであれば、メンバーごとに
切り出すことで対応してみて下さい。


Imports System.IO
Imports System.Text
----
Dim x As DATA

Dim reader As New BinaryReader(New MemoryStream(My.Resources.果物))
x.cd = reader.ReadInt32()
x.name = Encoding.GetEncoding("Shift_JIS").GetString(reader.ReadBytes(reader.ReadUInt16()))



項目数が多いようなら、FilePut / FileGet 互換のシリアライザを自作するか、
もしくは、リソースに埋め込むバイナリ形式そのものを変更することも
検討してみて下さい。下記にてシリアル化のサンプルが公開されています。
http://dobon.net/vb/dotnet/file/index.html
回答いつもありがとうございます。

構造体にInteger配列の場合はどのようにすれば良いのでしょうか。

Public Structure DATA
  Public cd as Integer
  Public name as String
  Public mise_flg() as Integer ←●追加しました
End Structure

Integer配列のときにReadInt32で取得すると
そこから取得した値がズレて変な値を取得してしまいました。

x.mise_flg(0) = reader.ReadInt32()
x.mise_flg(1) = reader.ReadInt32()
x.mise_flg(2) = reader.ReadInt32()

配列の場合は無理なのでしょうか。
■No32586に返信(ひろこさんの記事)
> 構造体にInteger配列の場合はどのようにすれば良いのでしょうか。

特に属性を付与していない配列の場合、FilePut 時のバイナリには
(2+8×次元数)分の記述子が先頭に配備され、その後に実データが並びます。

たとえば、
 .mise_flg = New Integer() {&H11223344, &H55667788, &H99AABBCC, &H12345678, &H90ABCDEF}
という要素数 5 個のデータを FilePut した場合、バイナリファイル上では
記述子に 10 バイト、データ部に 20 バイトが占有されます。

この場合の具体的なバイナリデータは、
 01,00,05,00,00,00,00,00,00,00,44,33,22,11,88,77,
 66,55,CC,BB,AA,99,78,56,34,12,EF,CD,AB,90,
です。

その内訳はこんな感じ。

 << 配列の次元数 >>
 01,00 : UInt16 の「1」。1次元配列を意味する。
  << 1 次元目の配列サイズ >>
  05,00,00,00 : UInt32 の「5」。Array.GetLength( 0 ) に相当。
  00,00,00,00 : Int32 の「0」。Array.GetLowerBound( 0 ) に相当。
 << 実データ部 >>
 44,33,22,11 : [0] Int32 で &H11223344
 88,77,66,55 : [1] Int32 で &H55667788
 CC,BB,AA,99 : [2] Int32 で &H99AABBCC
 78,56,34,12 : [3] Int32 で &H12345678
 EF,CD,AB,90 : [4] Int32 で &H90ABCDEF


なお、VB6 や VBA で作成したバイナリデータを読み込もうと
しているのであれば、インデックスが 0 ベースでない配列や、
固定長配列の扱いが異なる点に注意して下さい。

たとえば、VB6 で「ReDim .mise_flg(3 To 7)」としてファイルを
作成すると、mise_flg オフセットの+2バイト目〜+10バイト目が、
 05,00,00,00 : UInt32 の「5」
 03,00,00,00 : Int32 の「3」
となります。このファイルは、VB6 の Get #ステートメントでは読めますが、
VB.NET の FileGet メソッドではエラーとなります。
(.GetLowerBound が 3 ではなく 0 であれば、VB6 でも VB.NET でも OK)
詳しい説明ありがとうございます。
しかし私の頭では理解不能でした。

構造体に1次元配列や二次元配列があった場合、
色々と難しそうなのはわかりました。

私でも使える何かできあい関数があれば良いのですが・・・

バイナリーでは難しいのでテキストで考えてみます。

ありがとうございました。
■No32595に返信(ひろこさんの記事)
> 構造体に1次元配列や二次元配列があった場合、
> 色々と難しそうなのはわかりました。

ちなみに、先の

    Public Structure DATA
        Public cd As Integer
        Public name As String
        Public mise_flg() As Integer
    End Structure

の場合はこんな感じです。

Dim x As DATA

Dim reader As New BinaryReader(New MemoryStream(My.Resources.果物))
x.cd = reader.ReadInt32()
x.name = Encoding.GetEncoding("Shift_JIS").GetString(reader.ReadBytes(reader.ReadUInt16()))
If reader.ReadUInt16() = 1 Then
    Dim length As UInteger = reader.ReadUInt32()
    Dim lower As Integer = reader.ReadInt32()
    x.mise_flg = DirectCast(Array.CreateInstance(GetType(Integer), length), Integer())
    For i As Integer = 0 To x.mise_flg.GetUpperBound(0)
        x.mise_flg(i) = reader.ReadInt32()
    Next
Else
    x.mise_flg = Nothing
End If
reader.Close()


> バイナリーでは難しいのでテキストで考えてみます。
メモ帳等で作成しやすいのは、タブ区切りテキスト。
プログラムから扱いやすいのは、XML テキスト。


なお、FilePut で作成したバイナリー形式に拘らないのであれば、
BinaryWriter / BinaryReader を使って、自由なレイアウトの
バイナリー形式を構築できます。


> 私でも使える何かできあい関数があれば良いのですが・・・
最初の回答に示した「シリアル化」の手法では駄目だったのでしょうか?
構造体を丸ごと保持する場合には、かなり御手軽な手法かと思いますが…。
お返事遅くなり申し訳ありません。

ここまで教えていだだきありがとうございます。

一旦、頭を整理して考えてみます。

また質問するかもしれませんがその時は

またよろしくお願いいたします。

DOBON.NET | プログラミング道 | プログラミング掲示板