MemoryStream에서 문자열을 어떻게 얻습니까?


532

내가 MemoryStream로 채워 졌다는 메시지가 표시 String되면 어떻게 String되돌려 받을 수 있습니까?


1
reader.close가 항상 필요한지 확실하지 않습니다. 나는 과거에 문제가 있었기 때문에 원칙적으로 항상 안전을 지키기 위해 노력합니다.
Crusty

답변:


468

이 샘플은 문자열을 읽고 MemoryStream에 쓰는 방법을 보여줍니다.


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
어쨌든 함수가 범위를 벗어날 때 StreamWriter를 폐기하지 않습니까?
Tim Keating

14
변수가 범위를 벗어나면 Dispose가 호출되지 않습니다. GC가 도착하면 Finalize가 호출되지만 Dispose는 변수가 범위를 벗어나기 전에 호출해야합니다. StreamWriter와 StreamReader의 구현이 Dispose를 호출 할 필요가 없으며 호출을 기본 스트림으로 전달하기 때문에 위에서 호출하지 않습니다. 그러나 IDisposable을 구현하는 모든 항목에 대해 Dipose를 호출하면 합법적 인 주장을 할 수 있습니다. 향후 릴리스에서이를 폐기 할 필요는 없습니다.
Brian

12
@MichaelEakins 질문에 VB.Net으로 태그가 지정되어 있는데 왜 C #으로 응답해야합니까?
Rowland Shaw

1
처리 호출을 기본 스트림으로 전달하는 "도우미"에 대해 알게되어 기쁩니다. 그러나 이것은 잘못된 디자인 결정처럼 보입니다.
Gerard ONeill

2
이 결정은 나중에 완화되었습니다 : msdn.microsoft.com/en-us/library/…
Mark Sowul

310

당신은 또한 사용할 수 있습니다

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

나는 이것이 덜 효율적 이라고 생각 하지 않지만 맹세 할 수는 없었다. 또한 다른 인코딩을 선택할 수 있지만 StreamReader를 사용하면 해당 인코딩을 매개 변수로 지정해야합니다.


6
인코딩은 System.Text 네임 스페이스에 있습니다
northben

2
나는 이것과 동등한 PowerShell을 찾고 있었고 이것을 사용해야했습니다. ([System.Text.Encoding] :: ASCII) .GetString (ms.ToArray ())
Lewis

이 솔루션은 MemoryStream을 닫은 후에 사용할 수 있으므로 유용합니다.
Jacob Horbulyk

2
FWIW, 나는 이것이 매우 큰 현에서 작동하지 않는다는 것을 알았습니다 OutOfMemoryException. 사용하여이 StreamReader대신 문제를 해결했다.
Grant H.

이것은 함정이 될 수 있기 때문에 : 바이트 순서 표시를 인식하지 못하고 00문자열의 시작 부분에 16 진수가 포함될 수 있습니다 . 00 3C 3F-> .<?16 진수 편집기에서 VS 또는 메모장 ++에서 : <?. 따라서 문자열을 눈으로 비교하더라도 차이를 볼 수 없으며 비교 도구 또는 16 진 편집기 만 차이를 표시합니다. 여전히 그것을 사용한다면 String.TrimStart에 대해 생각하십시오. 참조 : docs.microsoft.com/en-us/dotnet/api/…
Skalli

99

StreamReader를 사용하여 MemoryStream을 문자열로 변환

<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
위치를 0으로 설정하면 메소드의 재사용 능력이 제한됩니다. 발신자가이를 관리하도록하는 것이 가장 좋습니다. 스트림에 문자열 이전의 데이터가 포함되어 있고 호출자가 처리 방법을 알고있는 경우에는 어떻게됩니까?
Alex Lyman

1
using 문을 사용하면 StreamReader가 폐기되지만 설명서에 따르면 StreamReader가 기본 스트림이 폐기되면 닫힙니다. 따라서 메서드는 전달 된 MemoryStream을 닫습니다 .MemoryStream을 의심하더라도 호출자는 개념적으로 불편합니다.
Trillian

당신이 올바른지. 일반적으로 스트림이 메서드에 매개 변수로 전달되는 경우 스트림 도우미 클래스에서 Dispose 메서드를 사용하는 것은 좋지 않습니다. 이 답변을 업데이트하겠습니다. 또한 아래에 더 완전한 답변이 있습니다.
Brian

해당 클래스를 디 컴파일하면 dispose 메소드가 인스턴스에서 null이 아닌 스트림 (TextWriter, MemoryStream 등)에서 Dispose ()를 호출하는 것을 볼 수 있습니다.
Sinaesthetic


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

인코딩이 관련된 경우에는 이전 솔루션이 작동하지 않았습니다. 여기에 "실제 생활"이 있습니다-예를 들어 이것을 올바르게하는 방법 ...

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

이 경우, 쉬운 방법으로 ReadToEnd메소드 를 실제로 MemoryStream사용하려면이 확장 메소드를 사용하여 다음을 수행 할 수 있습니다.

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

이 방법을 다음과 같이 사용할 수 있습니다.

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

이 샘플은 MemoryStream에서 문자열을 읽는 방법을 보여줍니다. 여기서 DataContractJsonSerializer를 사용하여 직렬화를 사용하고 일부 서버에서 클라이언트로 문자열을 전달한 다음 매개 변수로 전달 된 문자열에서 MemoryStream을 복구하는 방법 MemoryStream 직렬화를 해제합니다.

이 샘플을 수행하기 위해 다른 게시물의 일부를 사용했습니다.

이것이 도움이되기를 바랍니다.

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의 답변을 약간 수정하면 읽기 시작을 선택적으로 관리 할 수 ​​있습니다. 이것이 가장 쉬운 방법 인 것 같습니다. 아마도 가장 효율적이지는 않지만 이해하기 쉽고 사용하기 쉽습니다.

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의 대답에 새로운 것을 추가하지 않습니다
Luis Filipe

5

MemoryStream 타입에서 멋진 확장 방법을 만들어 보시겠습니까?

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

물론 이러한 방법을 표준 방법과 함께 사용할 때는주의하십시오. :) ... 동시성을 위해 편리한 streamLock을 사용해야합니다.


0

스트림을 작성 해야하는 클래스와 통합해야합니다.

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

다중 사용을 위해 코드 줄을 줄이는 데 도움이되는 간단한 클래스를 만듭니다.

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

그런 다음 샘플을 한 줄의 코드로 바꿀 수 있습니다

var ret = MemoryStreamStringWrapper.Write(schema.Write);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.