web-dev-qa-db-fra.com

Conversion de flux en chaîne et retour ... que nous manque-t-il?

Je veux sérialiser des objets en chaînes, et inversement.

Nous utilisons protobuf-net pour transformer un objet en un flux et inversement, avec succès.

Cependant, diffuser en chaîne et retour ... pas si réussi. Après avoir passé StreamToString et StringToStream, la nouvelle Stream n’est pas Désérialisée par protobuf-net; il déclenche une exception Arithmetic Operation resulted in an Overflow. Si nous désérialisons le flux d'origine, cela fonctionne.

Nos méthodes:

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

Notre exemple de code utilisant ces deux:

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

C'est si commun mais si profondément faux. Les données Protobuf ne sont pas des données de chaîne. Ce n'est certainement pas ASCII. Vous utilisez l'encodage à l'envers . Un encodage de texte transfère:

  • une chaîne arbitraire en octets formatés
  • octets formatés à la chaîne d'origine

Vous n'avez pas "octets formatés". Vous avez octets arbitraires. Vous devez utiliser quelque chose comme un code base-n (généralement: base-64). Cela transfère

  • octets arbitraires en chaîne formatée
  • une chaîne formatée aux octets d'origine

regardez Convert.ToBase64String et Convert. FromBase64String

51
Marc Gravell

Je viens de tester cela et fonctionne bien.

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

Si vous avez déjà écrit stream, vous voudrez peut-être aller au début avant de lire le texte: stream.Seek(0, SeekOrigin.Begin);

164
Ehsan

Lorsque vous testez, essayez avec UTF8 Encoder le flux comme ci-dessous 

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

Essaye ça.

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

une conversion de UTF8 MemoryStream en chaîne:

var res = Encoding.UTF8.GetString(stream.GetBuffer(),0 , stream.GetBuffer().Length)
3
Wolfgang Grinfeld

J'ai écrit une méthode utile pour appeler n'importe quelle action prenant une StreamWriter et l'écrire en chaîne. La méthode est comme ça;

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

Et vous pouvez l'utiliser comme ça;

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

Je sais que cela peut être fait beaucoup plus facilement avec un StringBuilder, le fait est que vous pouvez appeler n'importe quelle méthode prenant un StreamWriter.

2
Steztric

Je veux sérialiser des objets en chaînes, et inversement.

XmlSerializer est différent des autres réponses, mais le moyen le plus simple de faire exactement cela pour la plupart des types d'objet est:

        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
        }

Toutes vos propriétés publiques des types pris en charge seront sérialisées. Même certaines structures de collection sont prises en charge et seront intégrées aux propriétés de sous-objet. Vous pouvez contrôler le fonctionnement de la sérialisation avec attributs sur vos propriétés.

Cela ne fonctionne pas avec tous les types d'objet, certains types de données ne sont pas pris en charge pour la sérialisation, mais globalement, ils sont assez puissants et vous n'avez pas à vous soucier de l'encodage. 

0
Denise Skidmore

Dans le cas où vous voulez sérialiser/désérialiser des POCO, la bibliothèque JSON de Newtonsoft est vraiment bonne. Je l'utilise pour conserver les POCO dans SQL Server sous forme de chaînes JSON dans un champ nvarchar. La mise en garde est que puisque sa dé/sérialisation n'est pas vraie, il ne conservera pas les membres privés/protégés et la hiérarchie de classes. 

0
MD Luffy