从流中反序列化一定长度,而不是没有LengthPrefix的Stream的末尾

时间:2011-12-14 06:30:14

标签: protobuf-net

我正在尝试在解串通过ProtoBuf.Net存储的对象之前,有一种方法可以解决我在Stream中读取MemoryStream的问题。

我无法使用带有LengthPrefix功能的Protobuf.Net,因为我回来并在写入新记录时调整文件中的记录,以便可以向后或向前遍历文件。序列化类不需要更改,因为我将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

我希望我能够实现的是通过将Length to Read传递给Deserialize函数,然后我就可以取消整个MemoryStream块并让我的对象恢复。

我使用BinaryReader / Writer作为长度/偏移量,以便我可以稍后返回,只是用更新的值覆盖这些位置。

1 个答案:

答案 0 :(得分:1)

如果您使用的是v2,那么TypeModel API(实际上是主要API; Serializer.Deserialize<T> 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);

我还应该注意,“with length prefix”API也允许使用不同的前缀样式,固定长度(big-endian或little-endian)int32可用。但是你当前的方法也应该可以正常工作。

如果您使用v1,则可能必须制作长度受限的流....或仅borrow the one that v1 uses internally(请注意,v2不使用此方法 - 它会跟踪单个上的剩余活动字节流加缓冲区。)