前回は構造体をそのままで読み書きする例を示しましたが、 その中で構造体に配列を持っている場合にはマーシャルの考え方を使うとありましたので、 今回はバイト配列を2個持つ構造体をメモリマップドファイルに書込み、読込む例を示したいと思います。
今回も、メモリマップドファイルの指定で、実際のファイルへの書込みを行いますので、 書込んだ後で、エディタで確認することで、書き込んだデータの値の確認を行います。
以下のソースにその関数を記します。
このフォームは、ボタンを2個配置します。 Button1 は構造体を宣言し、中身を設定してから、構造体をマーシャリングにより、べたなバイト配列として展開します。
そのバイト配列をメモリマップドファイルに書込みを行います。 処理手順は以下の様になります。
1.オブジェクトのアンマネージのバイトサイズでバイト配列宣言
バイト配列を使ってメモリマップドファイルに書込みを行うので、最初に宣言する。
2.アンマネージメモリからメモリを割り当て
アンマネージメモリ(連続したバイト領域としての領域)を(1.)と同じ容量でメモリを確保する。
3.マネージオブジェクトからアンマネージメモリにデータをマーシャリング
構造体の内容を、アンマネージメモリに連続したバイト領域としてコピーする。
4.アンマネージメモリポインターのデータをマネージバイト配列にコピー
アンマネージメモリ(連続したバイト領域としての領域)の内容を、マネージバイト配列に展開する。 (マネージバイト配列はメモリ的には連続した領域に存在するわけでは無く、各配列バイトデータがバラバラに管理されている)
5.アンマネージ メモリから割り当てられたメモリを解放
アンマネージメモリに確保したメモリ領域を解放する。
6.アクセサを使ってメモリマップドファイルへの書込み
マネージバイト配列の内容をメモリマップドファイルへ書込みする。
Button2 はメモリマップドファイルから全体をバイト配列として読込みを行います。 そのバイト配列を、マーシャリングにより構造体に変換する処理を行っています。
処理手順は以下の様になります。
1.オブジェクトのアンマネージのバイトサイズでバイト配列宣言
バイト配列を使ってメモリマップドファイルに書込みを行うので、最初に宣言する。
2.アクセサを使ってメモリマップドファイルから読込
メモリマップドファイルからマネージバイト配列に読込みする。
3.アンマネージメモリからメモリを割り当て
アンマネージメモリ(連続したバイト領域としての領域)を(1.)と同じ容量でメモリを確保する。
4.マネージバイト配列をアンマネージメモリポインターにコピー
メモリマップドファイルから読込まれたマネージバイト配列の内容を、アンマネージメモリ(連続したバイト領域としての領域)に展開する。
5.アンマネージメモリブロックから、指定した型の、新しく割り当てられたマネージオブジェクトにデータをマーシャリング
連続したバイト領域のアンマネージメモリブロックから、指定された型の、マネージな領域にマーシャリングコピーする。
6.アンマネージメモリから割り当てられたメモリを解放
アンマネージメモリに確保したメモリ領域を解放する。
共有メモリとしてのメモリマップドファイルの使い方3・配列を持つ構造体の書込と読込
Imports System.IO
Imports System.IO.MemoryMappedFiles
Imports System.Text
Imports System.Runtime.InteropServices
Public Class frmMemMapStruc2
'1バイト境界の構造体
<StructLayout(LayoutKind.Sequential, Pack:=1)> _
Public Structure StrucTest
Const SIZE1 = 8
Const SIZE2 = 16
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=SIZE1)> _
Public arrData1() As Byte 'Byte型配列データ1
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=SIZE2)> _
Public arrData2() As Byte 'Byte型配列データ2
'初期化メソッド
Sub New(ByVal intDummy As Integer)
Me.arrData1 = New Byte(SIZE1 - 1) {}
Me.arrData2 = New Byte(SIZE2 - 1) {}
End Sub
End Structure
'バイト型配列を文字列に変換する
Private Function ConvBytesToString(ByVal pbytDatas() As Byte) As String
If pbytDatas(0) = 0 Then
Return ""
End If
'Trimされる文字(NULL文字、半角空白、全角空白)
Dim pchrTrim() As Char = {ControlChars.NullChar, " "c, " "c}
'Shift JISとして文字列に変換
Return System.Text.Encoding.GetEncoding(932).GetString(pbytDatas).Trim(pchrTrim)
End Function
'文字列をバイト配列に展開する
Private Sub ConvStringToBytes(ByVal astrData As String, ByRef abytArr() As Byte)
'文字列をShift-JISとしてバイト配列に変換
Dim pbytDatas() As Byte = System.Text.Encoding.GetEncoding(932).GetBytes(astrData)
'格納先バイト配列を0x00でクリア
Array.Clear(abytArr, 0, abytArr.Length)
'コピーバイト数の調整
Dim pintCopy As Integer = pbytDatas.Length
If pintCopy > abytArr.Length Then
pintCopy = abytArr.Length
End If
'格納先にコピー
Array.Copy(pbytDatas, abytArr, pintCopy)
End Sub
'テキストボックスの内容をメモリマップドファイルに書込む
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'メモリ上にメモリマップドファイルをオープンする
Dim mmf = MemoryMappedFile.CreateFromFile("MemMapFileTest.dat", FileMode.OpenOrCreate, "MemMapFileTest", 64)
'メモリマップドファイルのビューに対応するアクセサ生成
Dim acc As MemoryMappedViewAccessor = mmf.CreateViewAccessor()
'書込用の構造体の宣言
Dim StrucT As New StrucTest(0)
'ASCII文字列をバイト配列に展開する
ConvStringToBytes("1234567", StrucT.arrData1) '8バイト領域に7バイト設定
ConvStringToBytes("ABCDEFGHIJ", StrucT.arrData2) '16バイト領域に10バイト設定
'1.オブジェクトのアンマネージのバイトサイズでバイト配列宣言
Dim size As Integer = Marshal.SizeOf(StrucT)
Dim bytes(size) As Byte
'2.アンマネージメモリからメモリを割り当て
Dim ptr As IntPtr = Marshal.AllocHGlobal(size)
'3.マネージオブジェクトからアンマネージメモリにデータをマーシャリング
Marshal.StructureToPtr(StrucT, ptr, False)
'4.アンマネージ メモリ ポインターのデータを マネージバイト配列にコピー
Marshal.Copy(ptr, bytes, 0, size)
'5.アンマネージ メモリから割り当てられたメモリを解放
Marshal.FreeHGlobal(ptr)
'6.アクセサを使ってメモリマップドファイルへの書込み
acc.WriteArray(0, bytes, 0, bytes.Length)
'アクセサ、メモリマップドファイルの廃棄
acc.Dispose()
mmf.Dispose()
End Sub
'メモリマップドファイルの内容を読込んで表示する
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
'メモリ上にメモリマップドファイルをオープンする
Dim mmf = MemoryMappedFile.CreateFromFile("MemMapFileTest.dat", FileMode.OpenOrCreate, "MemMapFileTest", 64)
'メモリマップドファイルのビューに対応するアクセサ生成
Dim acc As MemoryMappedViewAccessor = mmf.CreateViewAccessor()
'読込用の構造体の宣言
Dim StrucT2 As StrucTest = Nothing
'1.オブジェクトのアンマネージのバイトサイズでバイト配列宣言
Dim size As Integer = Marshal.SizeOf(StrucT2)
Dim bytes(size) As Byte
'2.アクセサを使ってメモリマップドファイルから読込
acc.ReadArray(0, bytes, 0, size)
'3.アンマネージメモリからメモリを割り当て
Dim ptr As IntPtr = Marshal.AllocHGlobal(size)
'4.マネージバイト配列をアンマネージメモリポインターにコピー
Marshal.Copy(bytes, 0, ptr, size)
'5.アンマネージメモリブロックから、指定した型の、新しく割り当てられたマネージオブジェクトにデータをマーシャリング
StrucT2 = CType(Marshal.PtrToStructure(ptr, GetType(StrucTest)), StrucTest)
'6.アンマネージ メモリから割り当てられたメモリを解放
Marshal.FreeHGlobal(ptr)
'アクセサ、メモリマップドファイルの廃棄
acc.Dispose()
mmf.Dispose()
'バイト型配列を文字列に変換する
Dim strData As String = ""
strData &= "arrData1:" & ConvBytesToString(StrucT2.arrData1) & vbCrLf
strData &= "arrData2:" & ConvBytesToString(StrucT2.arrData2) & vbCrLf
MsgBox("Read Text:" & vbCrLf & strData)
End Sub
End Class
MemMapFileTest.dat のファイルの内容をバイナリ表示で行うと以下の様になっています。 (「秀丸エディタ」で表示)
関連する記事
⇒共有メモリとしてのメモリマップドファイルの使い方(MemoryMappedFile,CreateOrOpen,CreateViewAccessor)⇒共有メモリとしてのメモリマップドファイルの使い方2・構造体の書込と読込
コメント