Преобразование потока в строку и обратно... что нам не хватает?

Я хочу сериализовать объекты в строки и обратно.

Мы используем protobuf-net для успешного преобразования объекта в поток и обратно.

Однако Stream для строки и обратно... не так успешна. Пройдя StreamToString и StringToStream, новый Stream не будет десериализуется протобуф-сетью; он вызывает исключение 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);
}

Наш пример кода, используя следующие два:

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

Это так часто, но так глубоко ошибочно. Данные Protobuf не являются строковыми данными. Это, конечно, не ASCII. Вы используете кодировку назад. Текстовое кодирование переносит:

  • произвольная строка в отформатированные байты
  • отформатированные байты в исходную строку

У вас нет "отформатированных байтов". У вас есть произвольные байты. Вам нужно использовать что-то вроде base-n (обычно: base-64). Это переносит

  • произвольные байты в отформатированную строку
  • отформатированная строка к исходным байтам

посмотрите на Convert.ToBase64String и Convert. FromBase64String

Ответ 2

Я только что проверил это и отлично работал.

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

Ответ 3

При тестировании попробуйте с UTF8 Кодировать поток, как показано ниже

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

Ответ 4

Попробуйте это.

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

Ответ 5

преобразование MemoryStream в строку: UTF8:

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

Ответ 6

Я написал полезный метод для вызова любого действия, которое принимает 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.

Ответ 7

В usecase, где вы хотите сериализовать/десериализовать POCOs, библиотека Newtonsoft JSON действительно хороша. Я использую его для сохранения POCOs в SQL Server как строки JSON в поле nvarchar. Предостережение заключается в том, что, поскольку его не истинная де-сериализация, он не будет сохранять частные/защищенные члены и иерархию классов.

Ответ 8

Я хочу сериализовать объекты в строки и обратно.

В отличие от других ответов, но наиболее простым способом сделать это для большинства типов объектов является 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
        }

Все ваши открытые свойства поддерживаемых типов будут сериализованы. Даже некоторые структуры коллекций поддерживаются и будут туннелировать до свойств подобъекта. Вы можете контролировать, как сериализация работает с атрибутами в ваших свойствах.

Это не работает со всеми типами объектов, некоторые типы данных не поддерживаются для сериализации, но в целом это довольно мощный инструмент, и вам не нужно беспокоиться о кодировании.