web-dev-qa-db-ja.com

StreamからStringへの変換とその逆変換...何が足りないのでしょうか。

オブジェクトを文字列にシリアライズしたい、そして戻ってきたい。

Protobuf-netを使ってオブジェクトをStreamに変換したり戻したりすることに成功しました。

ただし、文字列へのストリーミングおよびその逆行...それほど成功しません。 StreamToStringStringToStreamを通過した後、新しいStreamはprotobuf-netによって逆シリアル化されません。それはArithmetic Operation resulted in an Overflow例外を発生させます。元のストリームを逆シリアル化しても、うまくいきます。

私たちの方法:

public static string StreamToString(Stream stream)
{
    stream.Position = 0;
    using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
    {
        return reader.ReadToEnd();
    }
}

public static Stream StringToStream(string src)
{
    byte[] byteArray = Encoding.UTF8.GetBytes(src);
    return new MemoryStream(byteArray);
}

これら2つを使ったサンプルコード:

MemoryStream stream = new MemoryStream();
Serializer.Serialize<SuperExample>(stream, test);
stream.Position = 0;
string strout = StreamToString(stream);
MemoryStream result = (MemoryStream)StringToStream(strout);
var other = Serializer.Deserialize<SuperExample>(result);
140
flipuhdelphia

これはとても一般的ですが非常に間違っています。プロトブフデータは文字列データではありません。それは確かにASCIIではありません。エンコーディングを逆方向に使用しています。テキストエンコーディングは次のものを転送します。

  • フォーマットされたバイトへの任意の文字列
  • 元の文字列にフォーマットされたバイト数

あなたは「フォーマットされたバイト」を持っていません。あなたは任意のバイトを持っています。 base-n(通常はbase-64)エンコードのようなものを使う必要があります。この転送

  • フォーマットされた文字列への任意のバイト
  • 元のバイトにフォーマットされた文字列

convert.ToBase64StringとConvertを見てください。 FromBase64String

52
Marc Gravell

これをテストしたばかりで、正常に動作します。

string test = "Testing 1-2-3";

// convert string to stream
byte[] byteArray = Encoding.ASCII.GetBytes(test);
MemoryStream stream = new MemoryStream(byteArray);

// convert stream to string
StreamReader reader = new StreamReader(stream);
string text = reader.ReadToEnd();

streamがすでに書き込まれている場合は、テキストを読み上げる前に、最初の前に先頭までシークすることをお勧めします。stream.Seek(0, SeekOrigin.Begin);

174
Ehsan

テストするときはUTF8 Encode streamで試してみてください。

var stream = new MemoryStream();
var streamWriter = new StreamWriter(stream, System.Text.Encoding.UTF8);
Serializer.Serialize<SuperExample>(streamWriter, test);
5
Damith

uTF8 MemoryStreamからStringへの変換:

var res = Encoding.UTF8.GetString(stream.GetBuffer(), 0 , (int)stream.Length)
5

これを試して。

string output1 = Encoding.ASCII.GetString(byteArray, 0, byteArray.Length)
5
user3588327

私はStreamWriterを取る任意のアクションを呼び出し、代わりにそれを文字列に書き出すための便利なメソッドを書きました。方法はこんな感じです。

static void SendStreamToString(Action<StreamWriter> action, out string destination)
{
    using (var stream = new MemoryStream())
    using (var writer = new StreamWriter(stream, Encoding.Unicode))
    {
        action(writer);
        writer.Flush();
        stream.Position = 0;
        destination = Encoding.Unicode.GetString(stream.GetBuffer(), 0, (int)stream.Length);
    }
}

そしてあなたはこれをこのように使うことができます。

string myString;

SendStreamToString(writer =>
{
    var ints = new List<int> {1, 2, 3};
    writer.WriteLine("My ints");
    foreach (var integer in ints)
    {
        writer.WriteLine(integer);
    }
}, out myString);

私はこれがStringBuilderでもっと簡単にできることを知っています、重要なのはStreamWriterを取るどんなメソッドでも呼び出すことができるということです。

2
Steztric

オブジェクトを文字列にシリアライズしたい、そして戻ってきたい。

他の答えとは異なりますが、ほとんどのオブジェクト型でこれを正確に行う最も簡単な方法はXmlSerializerです。

        Subject subject = new Subject();
        XmlSerializer serializer = new XmlSerializer(typeof(Subject));
        using (Stream stream = new MemoryStream())
        {
            serializer.Serialize(stream, subject);
            // do something with stream
            Subject subject2 = (Subject)serializer.Deserialize(stream);
            // do something with subject2
        }

サポートされている型のパブリックプロパティはすべてシリアル化されます。いくつかのコレクション構造もサポートされており、サブオブジェクトのプロパティにトンネルします。プロパティの 属性 でシリアル化がどのように機能するかを制御できます。

これはすべてのオブジェクト型で機能するわけではなく、データ型によっては直列化がサポートされていないものもありますが、全体的にはかなり強力であり、エンコードについて心配する必要はありません。

0
Denise Skidmore

POCOをシリアライズ/デシリアライズしたいユースケースでは、NewtonsoftのJSONライブラリは本当に良いです。 SQL Server内のPOCOをnvarcharフィールドのJSON文字列として保持するために使用します。警告は、それが真のデシリアライゼーションではないので、それがプライベート/プロテクトメンバーとクラス階層を保存しないということです。

0
MD Luffy