バイナリの追加方法がわかりません。
OpenMode.AppendにしてもFilePutでモードがおかしいとエラーになります。
Seekを使って最後にしようと思っても最後のバイト位置がわかりません。
バイナリの追記方法を教えてください。
.net2005を使ってます。
FileOpen(1, Test.bin, OpenMode.Binary)
Seek(1, ???)
FilePut(1, data)'データを追記
FileClose(1)
FileLenでファイルの長さがわかるから、それをSeekの引数にすればいいかも…
でも、この関数群はVB6.0との互換用ですから、FileStreamなりMy.FileSystemなり
使った方がいいかと思われます。
色々やってみましたがわかりません
Public Structure Data
Public data1 As Integer
Public data2 As Integer
Public data3 As Integer
End Structure
data.data1 = 0
data.data2 = 1
data.data3 = 2
My.Computer.FileSystem.WriteAllBytes _
(Test.bin, data, True)
これで書き込もうとしましたが
dataのところでエラーがでます。
dataをbyteの1次元配列にしないといけないようです。
このあたりがよくわからず断念。
次にBinaryWriterを使ってみましたが
Dim binWriter As New BinaryWriter( _
File.Open(test.bin, FileMode.Create))
Try
data.data1 = 0
data.data2 = 1
data.data3 = 2
binWriter.Write(data)
Finally
binWriter.Close()
End Try
dataのところでエラーがでます。
引数がオーバーロードが存在しないと言われました。
結局構造体では書込めないようです。
構造体を書き込む場合の手法とかどうやるんでしょうか?
構造体の場合、バイト型配列にしてから書き込む必要がありそうです。
Marshal.StructureToPtr メソッドを使って、IntPtr型に変換し
Marshal.Copy メソッドを使って、Byte型配列を取得するとか。
(Marshal.SizeOfで構造体のサイズを取得できる)
また、BinaryFormatterってなのもあるようです。(普通はこちらを使いそう)
やってみましたがうまく出来ません
Writeする直前のbyDataの中身が全て0になってます。
どこかおかしいところはありますか?
Dim data As Data
Dim byData(Marshal.SizeOf(data)) As Byte
Dim binWriter As New BinaryWriter( _
File.Open(test.bin, FileMode.Append))
Dim size As Integer = Marshal.SizeOf(data)
Dim ptr As IntPtr = Marshal.AllocHGlobal(size)
Try
data.data1 = 1
data.data2 = 2
data.data3 = 3
Marshal.StructureToPtr(data, ptr, True)
Marshal.Copy(byData, 0, ptr, size)
binWriter.Write(byData)
Finally
binWriter.Close()
End Try
Marshal.FreeHGlobal(ptr)
そもそも、C でやっていたように、ファイルに構造体をそっくり書き込む/ファイルか
ら構造体にごっそり読み込むというのは、.NET ではできない…ことはないけれど、標準
的な方法で無いということを、ずいぶん前に知りました。
構造体をファイルに書き込みたい場合、その構造体に ISerializable を実装させて、構
造体自身に行わせるのがよい気がします。
ISerializable 実装の中では、BinaryReader / BinaryWriter を使うのがよいでしょ
う。
> Marshal.Copy(byData, 0, ptr, size)
引数の指定が間違っています。
http://msdn2.microsoft.com/ja-jp/library/ms146631(VS.80).aspx
より
<MSDN>
Public Shared Sub Copy ( _
source As IntPtr, _
destination As Byte(), _
startIndex As Integer, _
length As Integer _
)
</MSDN>
一応試しに作ってみた。
Imports System
Imports System.IO
Imports System.Runtime.InteropServices
<StructLayout(LayoutKind.Sequential)> _
Public Structure Data
Public data1 As Integer
Public data2 As Integer
Public data3 As Integer
End Structure
Public Module Sample
Public Sub Main(ByVal args() As String)
Dim d As New Data
Dim binWriter As BinaryWriter
Try
d.data1 = 0
d.data2 = 1
d.data3 = 2
binWriter = New BinaryWriter( _
File.Open(test.bin, FileMode.Append))
binWriter.Write(StructureToBytes(d))
Finally
binWriter.Close()
End Try
End Sub
Private Function StructureToBytes(ByVal struct As Object) As Byte()
' 構造体のサイズ
Dim struct_size As Integer = Marshal.SizeOf(struct)
' アンマネージメモリの確保
Dim ptr As IntPtr = Marshal.AllocHGlobal(struct_size)
' 戻り値用の配列の作成
Dim bin As Byte() = New Byte(struct_size){}
' アンマネージメモリにマーシャリング
Marshal.StructureToPtr(struct, ptr, struct_size)
' アンマネージメモリから配列にコピー
Marshal.Copy(ptr, bin, 0, struct_size)
' アンマネージメモリの解放
Marshal.FreeHGlobal(ptr)
Return bin
End Function
End Module
サンプルありがとうございます。
おかげさまで書込みが出来ました。
>>Dim bin As Byte() = New Byte(struct_size){}
この部分は1バイト余分にかかれてたので
Dim bin As Byte() = New Byte(struct_size-1){}
と、修正しました。
なぜか指定数+1できているようです。
なぜこんな仕様なのか…
とにかく解決いたしました。
レスくれた皆さんありがとうございました。
>なぜか指定数+1できているようです。
VBの配列は 0~n で、要素数が n+1 であることを失念していました。
(C#やC++では 0~n-1 で、要素数が n)
ですので、
>Dim bin As Byte() = New Byte(struct_size-1){}
となるんですね。