Akışı Dize ve Geriye Dönüştürme… Neyi kaçırıyoruz?


162

Nesneleri dizgilere serpiştirmek istiyorum.

Bir nesneyi bir Akışa dönüştürmek ve başarıyla geri dönmek için protobuf-net kullanıyoruz.

Ancak, dize ve geri akış ... o kadar başarılı değil. Geçiyor sonra StreamToStringve StringToStreamyeni Streamprotobuf-net tarafından serisi kaldırılan değildir; bir Arithmetic Operation resulted in an Overflowistisna oluşturur. Orijinal akışın serisini kaldırırsak çalışır.

Yöntemlerimiz:

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

Bu ikisini kullanan örnek kodumuz:

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
MemoryStrea olmamalı?
Ehsan

Yanıtlar:


60

Bu çok yaygın ama çok yanlış. Protobuf verileri dize verisi değildir. Kesinlikle ASCII değil. Kodlamayı geriye doğru kullanıyorsunuz . Bir kodlama metni aktarır:

  • biçimlendirilmiş baytlara rasgele bir dize
  • orijinal dizeye biçimlendirilmiş bayt

"Biçimlendirilmiş bayt" yok. You have keyfi bayt . Base-n (yaygın olarak: base-64) kodlaması gibi bir şey kullanmanız gerekir. Bu transferler

  • biçimlendirilmiş bir dizeye rastgele bayt
  • orijinal baytlara biçimlendirilmiş bir dize

Convert.ToBase64String ve Convert'e bakın. FromBase64String


1
Bir kullanabilirsiniz BinaryFormatterbuna benzer, tuhaf örnek ?
Mart'ta drzaus

@drzaus hm ... belki hayır:> "İkili serileştirmede eşleştirilmemiş vekil karakterler kaybolur"
drzaus

211

Ben sadece test ve iyi çalışıyor.

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

Eğer streamzaten yazılmıştır, metni dışarı okumadan önce ilk önce başlayan etmek isteyebileceğimiz:stream.Seek(0, SeekOrigin.Begin);


Ve StreamReader okuyucu = yeni StreamReader (akış) etrafında bir blok kullanmayı unutmayın;
PRMan

7

UTF8 MemoryStream - String dönüştürme:

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

2
Bunun yerine ToArray () kullanın. Tampon, kullanılan verilerin boyutundan daha büyük olabilir. ToArray (), verilerin doğru boyutta bir kopyasını döndürür. var array = stream.ToArray(); var str = Encoding.UTF8.GetString(array, 0, array.Length);. Ayrıca bkz msdn.microsoft.com/en-us/library/...
Mortennobel

1
@ Mortennobel ToArray()bellekte yeni bir dizi ayırır ve verileri arabellekten kopyalar, bu da çok fazla veriyle uğraşıyorsanız ciddi sonuçları olabilir.
Levi Botelho

Stream.GetBuffer () yerine stream.Length kullanımını not edin. Ve Levi, ToArray () kullanmamanın nedenini doğru bir şekilde not etti.
Wolfgang Grinfeld

5

Test ederken UTF8Encode stream ile aşağıdaki gibi deneyin

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

5

Bunu dene.

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

2

Bir eylemi çağırmak StreamWriterve bunun yerine bir dizeye yazmak için yararlı bir yöntem yazdım . Yöntem şöyledir;

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

Ve bu şekilde kullanabilirsiniz;

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

Bunun bir ile çok daha kolay yapılabileceğini biliyorum StringBuilder, mesele a StreamWriter.


1

Nesneleri dizgilere serpiştirmek istiyorum.

Diğer cevaplardan farklı, ancak çoğu nesne türü için tam olarak bunu yapmanın en basit yolu 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
        }

Desteklenen türlerin tüm genel mülkleriniz serileştirilecektir. Bazı toplama yapıları bile desteklenir ve alt nesne özelliklerine kadar tünel oluşturur. Seri ile nasıl çalıştığını kontrol edebilirsiniz nitelikler mülklerinizde.

Bu, tüm nesne türleriyle çalışmaz, bazı veri türleri serileştirme için desteklenmez, ancak genel olarak oldukça güçlüdür ve kodlama konusunda endişelenmenize gerek yoktur.


0

POCO'ları serileştirmek / serileştirmek istediğiniz usecase'de Newtonsoft'un JSON kütüphanesi gerçekten iyi. Ben bir nvarchar alanında JSON dizeleri olarak SQL Server içindeki POCOs devam etmek için kullanın. Dikkat edilmesi gereken nokta, serileştirme / serileştirme gerçek olmadığından, özel / korunan üyeleri ve sınıf hiyerarşisini koruyamayacağıdır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.