Десериализовать из потока определенной длины, где это не конец потока без LengthPrefix - PullRequest
1 голос
/ 14 декабря 2011

Я пытаюсь выяснить, есть ли способ избавиться от чтения в моем потоке в MemoryStream перед десериализацией объекта, который был сохранен через ProtoBuf.Net.

Я не могу использоватьProtobuf.Net с функциями 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 Ответ

1 голос
/ 14 декабря 2011

Если вы используете v2, то это доступно в API TypeModel (который на самом деле является основным API; API Serializer.Deserialize<T> просто вызывает 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, вам, возможно, придется создать поток с ограниченной длиной .... или просто позаимствовать тот, который v1 использует внутри (обратите внимание, что v2 не использует этот подход - он отслеживает оставшиеся активные байты в одном потоке плюс буфер).

...