2

大きなオブジェクト(> 30MB)をMSMQキューに送信しようとしています。大量のデータがあるため、送信する前にオブジェクトをGZipで圧縮し、受信側で解凍するというアイデアを送信しようとしています。

ただし、圧縮されたストリームをmessage.BodyStreamプロパティに書き込むことは機能しているように見えますが、そこから読み取ることはできません。何が悪いのかわかりません。

Message l_QueueMessage = new Message();
l_QueueMessage.Priority = priority;

using (MessageQueue l_Queue = CreateQueue())
{
    GZipStream stream = new GZipStream(l_QueueMessage.BodyStream, CompressionMode.Compress);

    Formatter.Serialize(stream, message);

    l_Queue.Send(l_QueueMessage);
}

Formatterは、BinaryFormatterタイプのグローバルプロパティです。これは、送信/受信するオブジェクトのタイプ(「ProductItem」など)にシリアル化/逆シリアル化するために使用されます。

受信側は次のようになります。

GZipStream stream = new GZipStream(l_Message.BodyStream, CompressionMode.Decompress);

object decompressedObject = Formatter.Deserialize(stream);

ProductItem l_Item = decompressedObject as ProductItem;

m_ProductReceived(sender, new MessageReceivedEventArgs<ProductItem>(l_Item));

l_ProductQueue.BeginReceive();

EndOfStreamException "{"Unable to read beyond the end of the stream."}System.IO.BinaryReader.ReadByte()で逆シリアル化しようとしています

messageBodyStreamプロパティを使用して、実際にはmessage.Formatterを回避します。これは、GZipStreamで独自のser / deserメカニズムを使用しているため、何にも初期化されません。ただし、それが正しい方法かどうかはわかりません。

私は何が欠けていますか?ありがとう!

4

3 に答える 3

3

元のコードの問題は、GZip フッターを正しく書き込むために を閉じる必要があり、GZipStreamその後でのみ送信できることです。そうしないと、逆シリアル化できないバイトを送信することになります。それが、送信が後で行われる新しいコードが機能する理由でもあります。

于 2011-08-29T10:28:02.880 に答える
2

OK、私はこれを機能させました。重要なのは、受信側で圧縮解除されたストリームを byte[] 配列に変換することでした。その後、逆シリアル化が機能し始めました。

送信者コード (メッセージを送信する前にストリームが閉じられていることに注意してください):

using (MessageQueue l_Queue = CreateQueue())
{
    using (GZipStream stream = new GZipStream(l_QueueMessage.BodyStream, CompressionMode.Compress, true))
    {
        Formatter.Serialize(stream, message);
    }

    l_Queue.Send(l_QueueMessage);
}

受信側 (ストリームを byte[] に変換してから逆シリアル化する方法に注意してください):

using (GZipStream stream = new GZipStream(l_QueueMessage.BodyStream, CompressionMode.Decompress))
{
    byte[] bytes = ReadFully(stream);

    using (MemoryStream ms = new MemoryStream(bytes))
    {
        decompressedObject = Formatter.Deserialize(ms);
    }
}

それでも、これが Stream.CopyTo() ではなく ReadFully() 関数を使用して機能する理由はわかりません。誰かいますか?

ところで、ReadFully() は Stream から byte[] を作成する関数です。これについては、 http://www.yoda.arachsys.com/csharp/readbinary.htmlで Jon Skeet の功績を称えなければなりません。ありがとう!

于 2011-08-29T10:12:42.787 に答える
1

圧縮と送信を分離してみてください。

byte[] binaryBuffer = null;
using (MemoryStream compressedBody = new MemoryStream()) 
{
    using(GZipStream stream = new GZipStream(compressedBody, CompressionMode.Compress))
    {
        Formatter.Serialize(compressedBody, message); 
        binaryBuffer = compressedBody.GetBuffer();
    }
}

using (MessageQueue l_Queue = CreateQueue())        
{            
    l_QueueMessage.BodyStream.Write(binaryBuffer, 0, binaryBuffer.Length);
    l_QueueMessage.BodyStream.Seek(0, SeekOrigin.Begin);
    l_Queue.Send(l_QueueMessage);
}
于 2011-08-29T08:15:11.477 に答える