2011-12-14 5 views
1

ストリームを読み込んでMemoryStreamに読み込みを行う方法があるかどうかを確認しようとしています。 ProtoBuf.Net経由で保存されています。LengthPrefixなしでストリームの終わりではない一定の長さのストリームからデシリアライズする

Protobuf.Net With LengthPrefix機能を使用することはできません。新しいレコードが書き込まれるたびにファイルが戻ってきて、ファイルを前後に移動できるように調整するからです。シリアライズされたクラスは、3つの長さを実際のクラスとは別にしておくので、変更を必要としません。

これは中に私は現在のエントリを読み取るために使用しているコードです:私は達成することができるかもしれない期待していた何

Private Function ReadEntry(ByVal br As BinaryReader) As PacketErrorLogEntry 
    Dim activeRecord As PacketErrorLogEntry 

    Dim OffsetPrevious As UInt32 = br.ReadUInt32() 
    Dim RecordLength As UInt32 = br.ReadUInt32 
    Dim OffsetNext As UInt32 = br.ReadUInt32 
    Using ms As New MemoryStream 
     Dim readLength As UInt32 
     Dim bytesRead As UInt32 
     Dim writeBuffer As Byte() = CType(Array.CreateInstance(GetType(Byte), _ 
              4096), Byte()) 
     Dim bytesToRead As UInt32 = CType(writeBuffer.Length, UInt32) 
     If bytesToRead > RecordLength Then 
      bytesToRead = RecordLength 
     End If 
     bytesRead = 0 

     While readLength < RecordLength 
      bytesRead = CType(br.BaseStream.Read(writeBuffer, 0, _ 
           CType(bytesToRead, Integer)), UInt32) 
      ms.Write(writeBuffer, 0, CType(bytesRead, Integer)) 
      readLength += bytesRead 
     End While 

     ms.Flush() 
     ms.Position = 0 
     activeRecord = Serializer.Deserialize(Of PacketErrorLogEntry)(ms) 
     activeRecord.PreviousRecordLocation = OffsetPrevious 
     activeRecord.NextRecordLocation = OffsetNext 
    End Using 
    'activeRecord = Serializer.Deserialize(Of PacketErrorLogEntry)(br.BaseStream, RecordLength) 
    'activeRecord.PreviousRecordLocation = OffsetPrevious 
    'activeRecord.NextRecordLocation = OffsetNext 


    Return activeRecord 
End Function 

ことは、私はその後、逆シリアル化関数に読むために長さを渡すことですMemoryStreamブロック全体をなくし、オブジェクトを元に戻すことができます。

私は後で戻ってその位置を更新された値で上書きできるように、長さ/オフセットにBinaryReader/Writerを使用します。

答えて

1

v2を使用している場合、これはTypeModel API(実際にはプライマリAPIで、 APIはRuntimeTypeModel.Default.Deserializeを呼び出します)で利用できます。消費するバイト数を受け入れるオーバーロードがあります。このような方法ワンス(TypeModelインスタンス上で、最も可能性が高いRuntimeTypeModel.Default)です:

/// <summary> 
/// Applies a protocol-buffer stream to an existing instance (which may be null). 
/// </summary> 
/// <param name="type">The type (including inheritance) to consider.</param> 
/// <param name="value">The existing instance to be modified (can be null).</param> 
/// <param name="source">The binary stream to apply to the instance (cannot be null).</param> 
/// <param name="length">The number of bytes to consume.</param> 
/// <returns>The updated instance; this may be different to the instance argument if 
/// either the original instance was null, or the stream defines a known sub-type of the 
/// original instance.</returns> 
public object Deserialize(Stream source, object value, Type type, int length); 

私はまた、固定長(いずれかビッグエンディアンで、異なるプリフィックススタイルを許可する「の長さの接頭辞」APIことに注意すべきですまたはリトルエンディアン)int32が利用可能です。しかし、あなたの現在のアプローチもうまくいくはずです。

v1を使用している場合は、長さが制限されたストリーム....または単にborrow the one that v1 uses internallyを作成する必要があります(v2ではこの方法は使用されません。 )。

+0

これはすばらしいMarcのおかげです。これが正しい使い方であることを願っています。 (使用V2) のActiveRecord =新PacketErrorLogEntry ProtoBuf.Meta.RuntimeTypeModel.Default.Deserialize(br.BaseStreamは、ActiveRecordの、メソッドGetType(PacketErrorLogEntry)、ctype関数(LengthPrevious、整数))の呼び出し元のコードで –

+0

@Paul 'をデシリアライズ'、' null'( 'Nothing')を' value'パラメータに渡すより正確にマップします。既存の値( 'activeRecord')を渡すことは、' Merge 'を呼び出すことに近いです。しかし、それが新鮮で輝いている限り、どちらかといえばかなり同じものになるはずです( '= New PacketErrorLogEntry'など) –

関連する問題