-
文字列の連結は、簡単な文字列の場合には&(アンド)演算子を用いて行います。 この演算子は二項演算子の様に文字列の連結に使えますし、代入演算子的にも使用できます。 例としては、以下の様な感じです。
Dim strData as String = "ABC" '二項演算子の様に文字列連結 strData = strData & "DEF" '代入演算子の様に文字列連結 strData &= "HIJKLMN"&(アンド)演算子も使い方が簡単なので、特に速度を必要としない場合にはそのままで特に問題はありません。 この String 型データはそれ自身がオブジェクトであり、中身を変更できない様になっています。 つまり上の二項演算子の例では、「strData」に代入している様な形ですが、
内部的には「strData」の実体は最初の「strData」が持っていた文字列(オブジェクト)と連結したものを 新しいオブジェクトとして作成されます。 では最初の文字列(オブジェクト)はどうなるかと言いますと、システム的には使われないオブジェクトとして 廃棄される状態になります。 実際の廃棄はシステムが勝手に行いますので、心配はいらないのですが、この連結が行われると、どんどん内部的に 使われないオブジェクトが生成されてしまいます。
そこで、この欠点を補うのが StringBuilder クラスです。 StringBuilder は文字列のオブジェクトとしては1個のみ存在し、 そのオブジェクトに対して追加、削除、置換を行いますので上記の様な無駄なオブジェクが生成されずに 処理速度が向上します。
以下の例は、&(アンド)演算子を使った場合と、StringBuilder クラスを使った簡単な例を示します。
文字列の連結の簡単な例
'少ない文字列の連結例 Private Sub BtnStringAdd_Click(sender As Object, e As EventArgs) Handles BtnStringAdd.Click Console.WriteLine("...BtnStringAdd_Click") '===[&]を使った文字列の連結=== Dim strData As String = "" '数値0~9を"0"~"9"として追加連結(10回分の連結) For i As Integer = 0 To 9 strData = strData & i.ToString Next '文字列の左に付加 strData = "文字列:" & strData '表示 Console.WriteLine("[&]の連結:{0}/", strData) '===[StringBuilder]を使った文字列の連結=== Dim sbData As New System.Text.StringBuilder() '数値0~9を"0"~"9"として追加連結 For i As Integer = 0 To 9 sbData.Append(i.ToString) Next '表示 Console.WriteLine("[StringBuilder]の連結:{0}/", sbData.ToString()) End SubStringBuilder を使って速度がどの位向上するのかを例として以下に示します。 以下にそのソースを示します。
文字列の連結をStringBuilderで高速に行う
'回数の多い文字列の連結例 Private Sub BtnStringAddBig_Click(sender As Object, e As EventArgs) Handles BtnStringAddBig.Click Console.WriteLine("...BtnStringAddBig_Click") '文字列の宣言 Dim strData As String = "" '開始時刻 Dim tc As Integer = System.Environment.TickCount For i As Integer = 0 To 9 '数値0~9を"0"~"9"として10000回追加 For ii As Integer = 1 To 10000 strData = strData & i.ToString Next Next '処理時間表示(結果文字列は大きすぎるので表示しない) Console.WriteLine("処理時間:{0}ミリ秒", System.Environment.TickCount - tc) '文字列の宣言 Dim sbData As New System.Text.StringBuilder() tc = System.Environment.TickCount For i As Integer = 0 To 9 '数値0~9を"0"~"9"として10000回追加 For ii As Integer = 1 To 10000 sbData.Append(i.ToString) Next Next '処理時間表示(結果文字列は大きすぎるので表示しない) Console.WriteLine("処理時間:{0}ミリ秒", System.Environment.TickCount - tc) End Sub
結果は一目瞭然なのですが、実行時間として100倍ぐらい違います。 処理としては簡単な1万回の連結を10回のループで回していますが、結果的には10万回の文字列連結になりますので &では10万回の String オブジェクト生成が行われるので、時間が掛かる様です。
PR -
前回は構造体をそのままで読み書きする例を示しましたが、 その中で構造体に配列を持っている場合にはマーシャルの考え方を使うとありましたので、 今回はバイト配列を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 ClassMemMapFileTest.dat のファイルの内容をバイナリ表示で行うと以下の様になっています。 (「秀丸エディタ」で表示)
関連する記事
⇒共有メモリとしてのメモリマップドファイルの使い方(MemoryMappedFile,CreateOrOpen,CreateViewAccessor)
⇒共有メモリとしてのメモリマップドファイルの使い方2・構造体の書込と読込
-
メモリマップドファイルを使ったバイト配列の読み書きの記事は前回紹介しましたが、 今回は構造体をそのままで読み書きする例を示します。
尚、今回は、実際のデータファイルを指定する方法で、メモリマップドファイルを使います。 ファイルに書込んだ後で、「秀丸」などのエディタで内容を確認する為です。
以下のソースにその関数を記します。
このフォームは、ボタンを2個と、テキストボックスを1個配置します。 Button1 はテキストボックスの文字列をInteger型データに設定し、メモリマップドファイルへの書込み処理を行い、 Button2 はメモリマップドファイルから読込みを行います。
MemoryMappedFile.CreateFromFile は実際のファイル名とマップ名とメモリ領域のサイズを指定し、メモリマップドファイルのオープンを行います。 その後、MemoryMappedFile.CreateViewAccessor のアクセサを使って、メモリ空間への読み書きを行います。共有メモリとしてのメモリマップドファイルの使い方2・構造体の書込と読込
Imports System.IO Imports System.IO.MemoryMappedFiles Imports System.Runtime.InteropServices Public Class frmMemMapStruc '簡単な構造体 <StructLayout(LayoutKind.Sequential, Pack:=1)> _ Public Structure StrucTest Public bytData As Byte 'Byte型データ Public intData As Integer 'Integer型データ Public lngData As Long 'Long型データ Public dblData As Double 'Double型データ Public decData As Decimal 'Decimal型データ End Structure 'テキストボックスの内容をメモリマップドファイルに書込む Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'メモリ上にメモリマップドファイルをオープンする Dim mmf = MemoryMappedFile.CreateFromFile("MemMapFileTest.dat", FileMode.OpenOrCreate, "MemMapFileTest", 1024) 'メモリマップドファイルのビューに対応するアクセサ生成 Dim acc As MemoryMappedViewAccessor = mmf.CreateViewAccessor() '構造体宣言と値設定 Dim StrucT As StrucTest StrucT.bytData = &H55 StrucT.intData = CInt(Me.TextBox1.Text) StrucT.lngData = 1000000L StrucT.dblData = 200.123 StrucT.decData = 1000.456 'アクセサで構造体をメモリマップドファイルへ書込み acc.Write(0, StrucT) 'アクセサ、メモリマップドファイルの廃棄 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", 1024) 'メモリマップドファイルのビューに対応するアクセサ生成 Dim acc As MemoryMappedViewAccessor = mmf.CreateViewAccessor() 'アクセサで構造体にメモリマップドファイルから読込み Dim StrucT As StrucTest acc.Read(0, StrucT) 'アクセサ、メモリマップドファイルの廃棄 acc.Dispose() mmf.Dispose() '構造体の値を表示 Dim strData As String = "" strData &= "bytData:" & StrucT.bytData.ToString("X2") & vbCrLf strData &= "intData:" & StrucT.intData.ToString & vbCrLf strData &= "lngData:" & StrucT.lngData.ToString & vbCrLf strData &= "dblData:" & StrucT.dblData.ToString & vbCrLf strData &= "decData:" & StrucT.decData.ToString & vbCrLf MsgBox("Read:" & strData) End Sub End ClassMemMapFileTest.dat のファイルの内容をバイナリ表示で行うと以下の様になっています。 (「秀丸エディタ」で表示)
このソースで注意するのは、構造体のデータの読み書き処理が終わったところで、 アクセサ及び、メモリマップドファイルのインスタンスの廃棄を行っているところです。
この処理をしないと、各ボタンクリック処理でのプロセスがデータファイルを捕まえたままになって、 MemoryMappedFile.CreateFromFile のところでエラーが発生します。(ファイルのロックが掛かった様な状態)
以下がその様子を示す画像です。(ボタン1のクリック処理を行い、その後で、ボタン2のクリックを行った時の様子です)
書込み、及び読込みの処理を別々のプロセスに分けた場合に、書込み処理中に読込み処理が行われる可能性があります。 また、その逆も考えられますので、MemoryMappedFile.CreateFromFile でエラーが発生した場合には、その後の処理はしない方がいいと思います。
今回の構造体は単純なInteger型やLong型などの全て値型のデータ型ばかりなので、 配列データは出来ないものかと思って以下の様にソースを変更しました。 (Byte型配列データの部分を追加)Imports System.IO Imports System.IO.MemoryMappedFiles Imports System.Runtime.InteropServices Public Class frmMemMapStruc '簡単な構造体 <StructLayout(LayoutKind.Sequential, Pack:=1)> _ Public Structure StrucTest Public bytData As Byte 'Byte型データ Public intData As Integer 'Integer型データ Public lngData As Long 'Long型データ Public dblData As Double 'Double型データ Public decData As Decimal 'Decimal型データ Public arrData() As Byte 'Byte型配列データ End Structure 'テキストボックスの内容をメモリマップドファイルに書込む Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'メモリ上にメモリマップドファイルをオープンする Dim mmf = MemoryMappedFile.CreateFromFile("MemMapFileTest.dat", FileMode.OpenOrCreate, "MemMapFileTest", 1024) 'メモリマップドファイルのビューに対応するアクセサ生成 Dim acc As MemoryMappedViewAccessor = mmf.CreateViewAccessor() '構造体宣言と値設定 Dim StrucT As StrucTest StrucT.bytData = &H55 'StrucT.intData = 100 StrucT.intData = CInt(Me.TextBox1.Text) StrucT.lngData = 1000000L StrucT.dblData = 200.123 StrucT.decData = 1000.456 StrucT.arrData = {&H0, &H11, &H55, &HAA} 'アクセサで構造体をメモリマップドファイルへ書込み acc.Write(0, StrucT) 'アクセサ、メモリマップドファイルの廃棄 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", 1024) 'メモリマップドファイルのビューに対応するアクセサ生成 Dim acc As MemoryMappedViewAccessor = mmf.CreateViewAccessor() 'アクセサで構造体にメモリマップドファイルから読込み Dim StrucT As StrucTest acc.Read(0, StrucT) 'アクセサ、メモリマップドファイルの廃棄 acc.Dispose() mmf.Dispose() '構造体の値を表示 Dim strData As String = "" strData &= "bytData:" & StrucT.bytData.ToString("X2") & vbCrLf strData &= "intData:" & StrucT.intData.ToString & vbCrLf strData &= "lngData:" & StrucT.lngData.ToString & vbCrLf strData &= "dblData:" & StrucT.dblData.ToString & vbCrLf strData &= "decData:" & StrucT.decData.ToString & vbCrLf MsgBox("Read:" & vbCrLf & strData) End Sub End Class
このソースを実行すると以下の様にVBから叱られてしまいました。
アクセサの構造体の書き込みは、構造体の中に参照データが存在する時にはできない様です。 配列データは構造体の arrData 変数は配列データの実体を持っているわけでは無く、 ポインタ的な参照を持っているだけなので、当然だとは思います。
しかし、参照データを含む構造体の場合にはマーシャルの考え方を使えばできる様ですので、 後日また公開したいと思います。関連する記事
⇒共有メモリとしてのメモリマップドファイルの使い方(MemoryMappedFile,CreateOrOpen,CreateViewAccessor)
⇒共有メモリとしてのメモリマップドファイルの使い方3・配列を持つ構造体の書込と読込
-
プロセス間での通信を簡単に行いたい場合には、メモリマップドファイルが使えます。 メモリマップドファイルはその名の通り、プログラム上のメモリ空間にファイルを読込んで、連続したメモリ空間として取り扱えます。 そのメモリ空間を読み書きすることで、プロセス間の通信ができます。
今回は、実際のデータファイルを指定しない方法での、メモリマップドファイルの使い方を示します。
以下のソースにその関数を記します。
このフォームは、ボタンを2個と、テキストボックスを1個配置します。 Button1 はテキストボックスの文字列をメモリマップドファイルへの書込み処理を行い、 Button2 はメモリマップドファイルから読込みを行います。
MemoryMappedFile.CreateOrOpen はマップ名とメモリ領域のサイズを指定し、メモリマップドファイルのオープンを行います。 その後、MemoryMappedFile.CreateViewAccessor のアクセサを使って、メモリ空間への読み書きを行います。共有メモリとしてのメモリマップドファイルの使い方
Imports System.IO Imports System.IO.MemoryMappedFiles Imports System.Text Public Class frmMemMap 'テキストボックスの内容をメモリマップドファイルに書込む Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'メモリ上にメモリマップドファイルをオープンする Dim mmf As MemoryMappedFile = MemoryMappedFile.CreateOrOpen("MemMapFileTest", 1024) 'メモリマップドファイルのビューに対応するアクセサ生成 Dim acc As MemoryMappedViewAccessor = mmf.CreateViewAccessor() 'ASCII文字列をバイト配列に展開する Dim asciiBytes As Byte() = Encoding.ASCII.GetBytes(Me.TextBox1.Text.Trim) 'バイト配列の最後尾にNULL(0x00)設定 ReDim Preserve asciiBytes(UBound(asciiBytes) + 1) asciiBytes(UBound(asciiBytes)) = 0 'アクセサを使ってメモリマップドファイルへの書込み acc.WriteArray(0, asciiBytes, 0, asciiBytes.Length) End Sub 'メモリマップドファイルの内容を読込んで表示する Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click 'メモリ上にメモリマップドファイルをオープンする Dim mmf As MemoryMappedFile = MemoryMappedFile.CreateOrOpen("MemMapFileTest", 1024) 'メモリマップドファイルのビューに対応するアクセサ生成 Dim acc As MemoryMappedViewAccessor = mmf.CreateViewAccessor() Dim byteVal As Byte Dim index As Integer = 0 Dim sb As StringBuilder = New StringBuilder() Do 'アクセサを使ってメモリマップドファイルから位置指定での読込 byteVal = acc.ReadByte(index) If (byteVal = 0) Then 'NULLの時点で終了 Exit Do End If 'バイト値を文字に変換 Dim ascChar As Char = ChrW(byteVal) '文字列に加算 sb.Append(ascChar, 1) 'メモリマップドファイルの位置を進める index += 1 Loop MsgBox("Read Text:" & sb.ToString) End Sub End Classこのソースでは少し問題が有ります。テキストとしてASCII文字列しか扱えないので、 全角文字をテキストボックスに入れた場合には、期待した結果が得られません。
この件に関しては、後日解決したいと思います。
本日時間が在ったので Shift-JIS が扱える様に変更してみました。
メモリマップドファイルに書込むところで、文字列をバイト配列に展開する処理で、 エンコーディングを Shift-JIS として取得し、バイト配列に展開する様にします。
また、メモリマップドファイルから読込むところでは、バイト配列に取得した後で、 上記同様にエンコーディングを Shift-JIS としてバイト配列から文字列への変換を行います。
以下にそのソースを示します。共有メモリとしてのメモリマップドファイルの使い方
Imports System.IO Imports System.IO.MemoryMappedFiles Imports System.Text Public Class frmMemMap 'テキストボックスの内容をメモリマップドファイルに書込む Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'メモリ上にメモリマップドファイルをオープンする Dim mmf As MemoryMappedFile = MemoryMappedFile.CreateOrOpen("MemMapFileTest", 1024) 'メモリマップドファイルのビューに対応するアクセサ生成 Dim acc As MemoryMappedViewAccessor = mmf.CreateViewAccessor() 'Shift-JIS文字列をバイト配列に展開する Dim asciiBytes As Byte() = Encoding.GetEncoding("shift-jis").GetBytes(Me.TextBox1.Text.Trim) 'バイト配列の最後尾にNULL(0x00)設定 ReDim Preserve asciiBytes(UBound(asciiBytes) + 1) asciiBytes(UBound(asciiBytes)) = 0 'アクセサを使ってメモリマップドファイルへの書込み acc.WriteArray(0, asciiBytes, 0, asciiBytes.Length) End Sub 'メモリマップドファイルの内容を読込んで表示する Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click 'メモリ上にメモリマップドファイルをオープンする Dim mmf As MemoryMappedFile = MemoryMappedFile.CreateOrOpen("MemMapFileTest", 1024) 'メモリマップドファイルのビューに対応するアクセサ生成 Dim acc As MemoryMappedViewAccessor = mmf.CreateViewAccessor() Dim byteVal As Byte Dim index As Integer = 0 Dim arrBytes(0) As Byte Do 'アクセサを使ってメモリマップドファイルから位置指定での読込 byteVal = acc.ReadByte(index) If (byteVal = 0) Then 'NULLの時点で終了 Exit Do End If '配列に退避 ReDim Preserve arrBytes(index) arrBytes(index) = byteVal 'メモリマップドファイルの位置を進める index += 1 Loop 'バイト型配列を文字列に変換する Dim strData As String = Encoding.GetEncoding("shift-jis").GetString(arrBytes) MsgBox("Read Text:" & strData) End Sub End Class関連する記事
⇒共有メモリとしてのメモリマップドファイルの使い方2・構造体の書込と読込
⇒共有メモリとしてのメモリマップドファイルの使い方3・配列を持つ構造体の書込と読込
-
クラスや構造体のデータをそのままファイルに登録し、再度読み込んで利用したい場合があります。 この様な時に、クラスや構造体をそのままシリアライズ化し、バイナリ形式でファイルに書き込むことでできます。
今回は簡単な例として、クラスは3個のパブリックな要素を持っています。 このクラスにデータを書込むときには、3個の変数にデータを設定してから、 バイナリファイルへの書込関数と、バイナリファイルからの読込関数を呼出しています。 但し、クラスの宣言には <Serializable()> が必要です。
バイナリファイルへの書込関数では、指定されたファイルを FileStream クラスで生成オープンして、 BinaryFormatter クラスでシリアライズ化を行って書き込みます。
バイナリファイルからの読込関数でも、同様に指定されたファイルを FileStream クラスでオープンして、 BinaryFormatter クラスでストリームからのデータを逆シリアライズ化を行って読み込みます。
尚、この例を示すために、3個のボタンを貼り、テストの実行を行います。クラスや構造体のそのままのデータをシリアライズ化して保存する方法
Public Class frmSerialize '''''' シリアライズ化を行うクラス(仮のクラス) ''' <Serializable()> _ Public Class DataClass Public intNo As Integer '番号 Public strData1 As String 'データ1 Public strData2 As String 'データ2 End Class '''''' シリアライズ化関数 ''' ''' <param name="strFileName">書込みファイル名</param> ''' <param name="objPara">シリアライズ化するオブジェクト</param> '''True:OK、False:NG Public Function WriteObj(ByVal strFileName As String, ByVal objPara As Object) As Boolean '指定されたファイルをFileStreamクラスで生成オープン Dim fs As New System.IO.FileStream(strFileName, System.IO.FileMode.Create) 'BinaryFormatterクラス(オブジェクトのバイナリ形式でシリアル化および逆シリアル化クラス) Dim bf As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter Try 'オブジェクトをバイナリ形式でシリアル化 bf.Serialize(fs, objPara) Return True Catch ex As Runtime.Serialization.SerializationException Return False Finally fs.Close() End Try End Function '''''' デシリアライズ関数 ''' ''' <param name="strFileName">読込みファイル名</param> ''' <param name="objPara">結果を返すオブジェクト</param> '''True:OK、False:NG Public Function ReadObj(ByVal strFileName As String, ByRef objPara As Object) As Boolean '指定されたファイルをFileStreamクラスでオープン Dim fs As New System.IO.FileStream(strFileName, System.IO.FileMode.Open) 'BinaryFormatterクラス(オブジェクトのバイナリ形式でシリアル化および逆シリアル化クラス) Dim bf As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter Try '指定されたオブジェクトを逆シリアル化し、指定オブジェクトに返す objPara = bf.Deserialize(fs) Return True Catch ex As Runtime.Serialization.SerializationException Return False Finally fs.Close() End Try End Function ' ***** これ以降は上記の関数等をテストするボタン処理 ***** ' [シリアライズ化]ボタン処理 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 'クラスのインスタンス宣言 Dim dc As New DataClass 'クラスにデータ設定 dc.intNo = TextBox1.Text dc.strData1 = TextBox2.Text dc.strData2 = TextBox3.Text 'シリアライズ化(ファイルはデフォルトの位置) Dim blnRet As Boolean = WriteObj("DataFile.dat", dc) End Sub ' [逆シリアライズ化]ボタン処理 Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click Dim obj As Object = Nothing Dim blnRet As Boolean = ReadObj("DataFile.dat", obj) If blnRet = True Then Dim dc As DataClass = DirectCast(obj, DataClass) TextBox1.Text = dc.intNo TextBox2.Text = dc.strData1 TextBox3.Text = dc.strData2 End If End Sub Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click TextBox1.Text = "" TextBox2.Text = "" TextBox3.Text = "" End Sub End Class
結果これを実行すると以下の様になります。関連する記事
⇒バイト配列を介したバイナリファイルの読込・書込処理について