Stream in String und zurück konvertieren ... was fehlt uns?


162

Ich möchte Objekte in Zeichenfolgen und zurück serialisieren.

Wir verwenden protobuf-net, um ein Objekt erfolgreich in einen Stream und zurück zu verwandeln.

Stream zu String und zurück ... nicht so erfolgreich. Nach dem Durchlaufen von StreamToStringund StringToStreamwird das Neue Streamnicht von protobuf-net deserialisiert. es wird eine Arithmetic Operation resulted in an OverflowAusnahme ausgelöst . Wenn wir den ursprünglichen Stream deserialisieren, funktioniert es.

Unsere Methoden:

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);
}

Unser Beispielcode mit diesen beiden:

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);

1
sollte Stream nicht MemoryStrea sein?
Ehsan

Antworten:


60

Das ist so üblich, aber so zutiefst falsch. Protobuf-Daten sind keine Zeichenfolgendaten. Es ist sicherlich nicht ASCII. Sie verwenden die Codierung rückwärts . Eine Textcodierung überträgt:

  • eine beliebige Zeichenfolge für formatierte Bytes
  • formatierte Bytes zur ursprünglichen Zeichenfolge

Sie haben keine "formatierten Bytes". Sie haben beliebige Bytes . Sie müssen so etwas wie eine Base-n-Codierung (normalerweise Base-64) verwenden. Dies überträgt

  • beliebige Bytes zu einer formatierten Zeichenfolge
  • Eine formatierte Zeichenfolge für die ursprünglichen Bytes

Schauen Sie sich Convert.ToBase64String und Convert an. FromBase64String


1
Könnten Sie ein verwenden BinaryFormatter, ähnlich wie dieses seltsame Beispiel ?
Drzaus

@drzaus hm ... vielleicht nicht:> "Alle ungepaarten
Ersatzzeichen

210

Ich habe das gerade getestet und funktioniert gut.

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();

Wenn streambereits geschrieben wurde, möchten Sie möglicherweise zuerst den Anfang suchen, bevor Sie den Text vorlesen:stream.Seek(0, SeekOrigin.Begin);


Und vergessen Sie nicht einen Verwendungsblock um StreamReader reader = new StreamReader (stream);
PRMan

7

eine Konvertierung von UTF8 MemoryStream in String:

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

2
Verwenden Sie stattdessen ToArray (). Der Puffer kann größer sein als die Größe der verwendeten Daten. ToArray () gibt eine Kopie der Daten mit der richtigen Größe zurück. var array = stream.ToArray(); var str = Encoding.UTF8.GetString(array, 0, array.Length);. Siehe auch msdn.microsoft.com/en-us/library/…
Mortennobel

1
@Mortennobel weist ToArray()ein neues Array im Speicher zu und kopiert Daten aus dem Puffer, was schwerwiegende Auswirkungen haben kann, wenn Sie mit vielen Daten arbeiten.
Levi Botelho

Beachten Sie die Verwendung von stream.Length anstelle von stream.GetBuffer (). Length. Und Levi hat den Grund für die Nichtverwendung von ToArray () richtig notiert.
Wolfgang Grinfeld

5

Versuchen Sie es beim Testen mit dem folgenden UTF8Encode-Stream

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

5

Versuche dies.

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

2

Ich habe eine nützliche Methode geschrieben, um jede Aktion, die a StreamWriterausführt, aufzurufen und stattdessen in eine Zeichenfolge zu schreiben. Die Methode ist wie folgt;

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);
    }
}

Und Sie können es so verwenden;

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);

Ich weiß, dass dies mit a viel einfacher gemacht werden StringBuilderkann. Der Punkt ist, dass Sie jede Methode aufrufen können, die a benötigt StreamWriter.


1

Ich möchte Objekte in Zeichenfolgen und zurück serialisieren.

Anders als die anderen Antworten, aber der einfachste Weg, genau das für die meisten Objekttypen zu tun, ist 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
        }

Alle Ihre öffentlichen Eigenschaften der unterstützten Typen werden serialisiert. Sogar einige Sammlungsstrukturen werden unterstützt und werden zu Unterobjekteigenschaften getunnelt. Sie können steuern, wie die Serialisierung mit Attributen in Ihren Eigenschaften funktioniert .

Dies funktioniert nicht mit allen Objekttypen, einige Datentypen werden für die Serialisierung nicht unterstützt, aber insgesamt ist es ziemlich leistungsfähig und Sie müssen sich nicht um die Codierung kümmern.


0

In dem Fall, in dem Sie POCOs serialisieren / deserialisieren möchten, ist die JSON-Bibliothek von Newtonsoft wirklich gut. Ich verwende es, um POCOs in SQL Server als JSON-Zeichenfolgen in einem nvarchar-Feld beizubehalten. Vorsichtsmaßnahme ist, dass private / geschützte Mitglieder und Klassenhierarchien nicht erhalten bleiben, da dies keine echte De- / Serialisierung ist.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.