MemoryStream'den bir dize nasıl alırsınız?


532

Bana MemoryStreamnüfuslu olduğunu bildiğim bir bilgi verilirse String, nasıl Stringgeri dönebilirim?


1
Reader.close'un her zaman gerekli olup olmadığından asla emin değilsiniz. Geçmişte sorunlarım oldu, bu yüzden kural olarak her zaman sadece güvenli tarafta olmak için yapıyorum.
Crusty

Yanıtlar:


468

Bu örnek, bir MemoryStream öğesine bir dizenin nasıl okunacağını ve yazılacağını gösterir.


Imports System.IO

Module Module1
  Sub Main()
    ' We don't need to dispose any of the MemoryStream 
    ' because it is a managed object. However, just for 
    ' good practice, we'll close the MemoryStream.
    Using ms As New MemoryStream
      Dim sw As New StreamWriter(ms)
      sw.WriteLine("Hello World")
      ' The string is currently stored in the 
      ' StreamWriters buffer. Flushing the stream will 
      ' force the string into the MemoryStream.
      sw.Flush()
      ' If we dispose the StreamWriter now, it will close 
      ' the BaseStream (which is our MemoryStream) which 
      ' will prevent us from reading from our MemoryStream
      'sw.Dispose()

      ' The StreamReader will read from the current 
      ' position of the MemoryStream which is currently 
      ' set at the end of the string we just wrote to it. 
      ' We need to set the position to 0 in order to read 
      ' from the beginning.
      ms.Position = 0
      Dim sr As New StreamReader(ms)
      Dim myStr = sr.ReadToEnd()
      Console.WriteLine(myStr)

      ' We can dispose our StreamWriter and StreamReader 
      ' now, though this isn't necessary (they don't hold 
      ' any resources open on their own).
      sw.Dispose()
      sr.Dispose()
    End Using

    Console.WriteLine("Press any key to continue.")
    Console.ReadKey()
  End Sub
End Module

3
İşlev yine de kapsam dışına çıktığında StreamWriter'ı atmayacak mı?
Tim Keating

14
Değişken kapsam dışına çıktığında imha çağrılmaz. Sonuçlandırma GC ona ulaştığında çağrılır, ancak Dispose değişken kapsam dışına çıkmadan önce çağrılması gereken bir şeydir. StreamWriter ve StreamReader uygulamasının Dispose çağrılmasını gerektirmediğini biliyorum, sadece çağrıyı temel akışa aktarıyor. Ancak, gelecekteki bir sürümün atılmasını gerektirmeyeceğini garanti edemediğiniz için Dipoz'u IDisposable uygulayan herhangi bir şey için çağırmak için meşru bir argüman yapılabilir.
Brian

12
@MichaelEakins Soru VB.Net olarak etiketlendiğinde neden cevap C # 'da olmalı?
Rowland Shaw

1
"Yardımcılar" ı altta yatan akarsulara atma çağrısını aktarırken öğrendiğime sevindim, ama bu kötü bir tasarım kararı gibi görünüyor.
Gerard ONeill

2
Bu karar daha sonra şu şekilde hafifletildi: msdn.microsoft.com/en-us/library/…
Mark Sowul

310

Ayrıca kullanabilirsiniz

Encoding.ASCII.GetString(ms.ToArray());

Bunun daha az verimli olduğunu düşünmüyorum , ama buna yemin edemedim. Ayrıca farklı bir kodlama seçmenize izin verirken, StreamReader'ı kullanarak bunu bir parametre olarak belirtmeniz gerekir.


6
Kodlama
Sistemde. Metin

2
Bunun PowerShell eşdeğerini arıyordum ve bunu kullanmak zorunda kaldım. ([System.Text.Encoding] :: ASCII) .GetString (ms.ToArray ())
Lewis

Bu çözüm, MemoryStream kapatıldıktan sonra kullanılabileceğinden faydalıdır.
Jacob Horbulyk

2
FWIW, bunun çok büyük dizelerle çalışmadığını gördüm, alıyorum OutOfMemoryException. StreamReaderBunun yerine bir sorunu kullanmak sorunu çözdü.
Grant H.

Bu bir tuzak olabilir: Bayt sırası işaretinin farkında değildir 00ve dizenin başına bir Hex içerebilir . 00 3C 3F-> .<?++ Hex Editor ama VS veya Not Defteri'nde: <?. Böylece, dizeleri gözle karşılaştırsanız bile farkı göremezsiniz, farkı yalnızca bir karşılaştırma aracı veya Hex editörü gösterecektir. Hala kullanıyorsanız String.TrimStart'ı düşünün. Bakınız: docs.microsoft.com/tr-tr/dotnet/api/…
Skalli

99

MemoryStream öğesini bir Dizeye dönüştürmek için StreamReader kullanma.

<Extension()> _
Public Function ReadAll(ByVal memStream As MemoryStream) As String
    ' Reset the stream otherwise you will just get an empty string.
    ' Remember the position so we can restore it later.
    Dim pos = memStream.Position
    memStream.Position = 0

    Dim reader As New StreamReader(memStream)
    Dim str = reader.ReadToEnd()

    ' Reset the position so that subsequent writes are correct.
    memStream.Position = pos

    Return str
End Function

3
Konum'u 0 olarak ayarlamak, yöntemin yeniden kullanım yeteneğini sınırlar - arayanın bunu yönetmesine izin vermek en iyisidir. Akış, arayanın nasıl işleneceğini bildiği dizeden önce veri içeriyorsa ne olur?
Alex Lyman

1
Using ifadesi, StreamReader'ınızın atılmasını sağlar, ancak belgeler StreamReader'ın atıldığında temeldeki akışı kapattığını söyler. Bu nedenle, yönteminiz MemoryStream.Dispose çok şüphe duysam bile arayanlar için kavramsal olarak serin olan MemoryStream kapatır, kapatır.
Trillian

Haklısın. Özellikle akış bir yönteme parametre olarak geçirilirse, akış yardımcı sınıflarında Dispose yöntemini kullanmak genellikle kötü bir fikirdir. Bu cevabı güncelleyeceğim. Ayrıca aşağıda daha eksiksiz bir cevabım var.
Brian

Bu sınıfları
kodalıyorsanız


26
byte[] array = Encoding.ASCII.GetBytes("MyTest1 - MyTest2");
MemoryStream streamItem = new MemoryStream(array);

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

22

Kodlamanın yer aldığı durumlarda önceki çözümler işe yaramaz. İşte - bir çeşit "gerçek hayat" - bunun nasıl doğru bir şekilde yapılacağı örneği ...

using(var stream = new System.IO.MemoryStream())
{
  var serializer = new DataContractJsonSerializer(typeof(IEnumerable<ExportData>),  new[]{typeof(ExportData)}, Int32.MaxValue, true, null, false);               
  serializer.WriteObject(stream, model);  


  var jsonString = Encoding.Default.GetString((stream.ToArray()));
}

15

Bu durumda, ReadToEndyöntemi gerçekten MemoryStreamkolay bir şekilde kullanmak istiyorsanız, bunu elde etmek için bu Uzantı Yöntemini kullanabilirsiniz:

public static class SetExtensions
{
    public static string ReadToEnd(this MemoryStream BASE)
    {
        BASE.Position = 0;
        StreamReader R = new StreamReader(BASE);
        return R.ReadToEnd();
    }
}

Ve bu yöntemi şu şekilde kullanabilirsiniz:

using (MemoryStream m = new MemoryStream())
{
    //for example i want to serialize an object into MemoryStream
    //I want to use XmlSeralizer
    XmlSerializer xs = new XmlSerializer(_yourVariable.GetType());
    xs.Serialize(m, _yourVariable);

    //the easy way to use ReadToEnd method in MemoryStream
    MessageBox.Show(m.ReadToEnd());
}

11

Bu örnek, bir serileştirme (DataContractJsonSerializer kullanarak) kullandığım, dizeyi bazı sunucudan istemciye geçirdiğim ve daha sonra parametre olarak iletilen dizeden MemoryStream'in nasıl kurtarılacağı MemoryStream'den bir dizenin nasıl okunacağını gösterir. , MemoryStream öğesinin serisini kaldırın.

Bu örneği gerçekleştirmek için farklı gönderilerin parçalarını kullandım.

Umarım bu yardımcı olur.

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Threading;

namespace JsonSample
{
    class Program
    {
        static void Main(string[] args)
        {
            var phones = new List<Phone>
            {
                new Phone { Type = PhoneTypes.Home, Number = "28736127" },
                new Phone { Type = PhoneTypes.Movil, Number = "842736487" }
            };
            var p = new Person { Id = 1, Name = "Person 1", BirthDate = DateTime.Now, Phones = phones };

            Console.WriteLine("New object 'Person' in the server side:");
            Console.WriteLine(string.Format("Id: {0}, Name: {1}, Birthday: {2}.", p.Id, p.Name, p.BirthDate.ToShortDateString()));
            Console.WriteLine(string.Format("Phone: {0} {1}", p.Phones[0].Type.ToString(), p.Phones[0].Number));
            Console.WriteLine(string.Format("Phone: {0} {1}", p.Phones[1].Type.ToString(), p.Phones[1].Number));

            Console.Write(Environment.NewLine);
            Thread.Sleep(2000);

            var stream1 = new MemoryStream();
            var ser = new DataContractJsonSerializer(typeof(Person));

            ser.WriteObject(stream1, p);

            stream1.Position = 0;
            StreamReader sr = new StreamReader(stream1);
            Console.Write("JSON form of Person object: ");
            Console.WriteLine(sr.ReadToEnd());

            Console.Write(Environment.NewLine);
            Thread.Sleep(2000);

            var f = GetStringFromMemoryStream(stream1);

            Console.Write(Environment.NewLine);
            Thread.Sleep(2000);

            Console.WriteLine("Passing string parameter from server to client...");

            Console.Write(Environment.NewLine);
            Thread.Sleep(2000);

            var g = GetMemoryStreamFromString(f);
            g.Position = 0;
            var ser2 = new DataContractJsonSerializer(typeof(Person));
            var p2 = (Person)ser2.ReadObject(g);

            Console.Write(Environment.NewLine);
            Thread.Sleep(2000);

            Console.WriteLine("New object 'Person' arrived to the client:");
            Console.WriteLine(string.Format("Id: {0}, Name: {1}, Birthday: {2}.", p2.Id, p2.Name, p2.BirthDate.ToShortDateString()));
            Console.WriteLine(string.Format("Phone: {0} {1}", p2.Phones[0].Type.ToString(), p2.Phones[0].Number));
            Console.WriteLine(string.Format("Phone: {0} {1}", p2.Phones[1].Type.ToString(), p2.Phones[1].Number));

            Console.Read();
        }

        private static MemoryStream GetMemoryStreamFromString(string s)
        {
            var stream = new MemoryStream();
            var sw = new StreamWriter(stream);
            sw.Write(s);
            sw.Flush();
            stream.Position = 0;
            return stream;
        }

        private static string GetStringFromMemoryStream(MemoryStream ms)
        {
            ms.Position = 0;
            using (StreamReader sr = new StreamReader(ms))
            {
                return sr.ReadToEnd();
            }
        }
    }

    [DataContract]
    internal class Person
    {
        [DataMember]
        public int Id { get; set; }
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public DateTime BirthDate { get; set; }
        [DataMember]
        public List<Phone> Phones { get; set; }
    }

    [DataContract]
    internal class Phone
    {
        [DataMember]
        public PhoneTypes Type { get; set; }
        [DataMember]
        public string Number { get; set; }
    }

    internal enum PhoneTypes
    {
        Home = 1,
        Movil = 2
    }
}

5

Brian'ın cevabının biraz değiştirilmiş bir versiyonu isteğe bağlı okuma başlangıcı yönetimine izin veriyor, Bu en kolay yöntem gibi görünüyor. muhtemelen en verimli değil, ama anlaşılması ve kullanımı kolaydır.

Public Function ReadAll(ByVal memStream As MemoryStream, Optional ByVal startPos As Integer = 0) As String
    ' reset the stream or we'll get an empty string returned
    ' remember the position so we can restore it later
    Dim Pos = memStream.Position
    memStream.Position = startPos

    Dim reader As New StreamReader(memStream)
    Dim str = reader.ReadToEnd()

    ' reset the position so that subsequent writes are correct
    memStream.Position = Pos

    Return str
End Function

3
Brian cevabına gerçekten yeni bir şey eklemiyor
Luis Filipe

5

MemoryStream türünde neden güzel bir uzantı yöntemi yapmıyorsunuz?

public static class MemoryStreamExtensions
{

    static object streamLock = new object();

    public static void WriteLine(this MemoryStream stream, string text, bool flush)
    {
        byte[] bytes = Encoding.UTF8.GetBytes(text + Environment.NewLine);
        lock (streamLock)
        {
            stream.Write(bytes, 0, bytes.Length);
            if (flush)
            {
                stream.Flush();
            }
        }
    }

    public static void WriteLine(this MemoryStream stream, string formatString, bool flush, params string[] strings)
    {
        byte[] bytes = Encoding.UTF8.GetBytes(String.Format(formatString, strings) + Environment.NewLine);
        lock (streamLock)
        {
            stream.Write(bytes, 0, bytes.Length);
            if (flush)
            {
                stream.Flush();
            }
        }
    }

    public static void WriteToConsole(this MemoryStream stream)
    {
        lock (streamLock)
        {
            long temporary = stream.Position;
            stream.Position = 0;
            using (StreamReader reader = new StreamReader(stream, Encoding.UTF8, false, 0x1000, true))
            {
                string text = reader.ReadToEnd();
                if (!String.IsNullOrEmpty(text))
                {
                    Console.WriteLine(text);
                }
            }
            stream.Position = temporary;
        }
    }
}

Tabii ki, bu yöntemleri standart yöntemlerle birlikte kullanırken dikkatli olun. :) ... eşzamanlılık için bu kullanışlı streamLock'u kullanmanız gerekir.


0

Üzerine yazmak için akışa ihtiyaç duyan bir sınıfla bütünleşmem gerekiyor:

XmlSchema schema;
// ... Use "schema" ...

var ret = "";

using (var ms = new MemoryStream())
{
    schema.Write(ms);
    ret = Encoding.ASCII.GetString(ms.ToArray());
}
//here you can use "ret"
// 6 Lines of code

Ben katları kullanmak için kod satırlarını azaltmak için yardımcı olabilir basit bir sınıf oluşturmak:

public static class MemoryStreamStringWrapper
{
    public static string Write(Action<MemoryStream> action)
    {
        var ret = "";
        using (var ms = new MemoryStream())
        {
            action(ms);
            ret = Encoding.ASCII.GetString(ms.ToArray());
        }

        return ret;
    }
}

sonra örneği tek bir kod satırı ile değiştirebilirsiniz

var ret = MemoryStreamStringWrapper.Write(schema.Write);
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.