คุณจะรับสตริงจาก 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 เมื่อฟังก์ชั่นออกนอกขอบเขตหรือไม่
ทิมคีด

14
การกำจัดไม่ได้ถูกเรียกเมื่อตัวแปรออกนอกขอบเขต การสรุปจะถูกเรียกเมื่อ GC เข้าใกล้มัน แต่การกำจัดเป็นสิ่งที่ต้องถูกเรียกก่อนที่ตัวแปรจะออกนอกขอบเขต ฉันไม่ได้เรียกข้างต้นเพราะฉันรู้ว่าการใช้งาน StreamWriter และ StreamReader ไม่ต้องการ Dispose ให้เรียกมันก็แค่ส่งสายไปยังสตรีมพื้นฐาน อย่างไรก็ตามคุณสามารถสร้างอาร์กิวเมนต์ที่ถูกต้องตามกฎหมายสำหรับการเรียก Dipose สำหรับสิ่งใดก็ตามที่ใช้ IDisposable เนื่องจากคุณไม่สามารถรับประกันได้ว่าจะมีการปล่อยรุ่นต่อ ๆ ไปในอนาคต
Brian

12
@MichaelEakins ทำไมคำตอบควรอยู่ใน C # เมื่อคำถามถูกแท็กเป็น VB.Net?
Rowland Shaw

1
ฉันดีใจที่ฉันได้เรียนรู้เกี่ยวกับ "ผู้ช่วยเหลือ" ผ่านการโทรไปยังสตรีมพื้นฐานของพวกเขา แต่นี่เป็นการตัดสินใจที่ไม่ดี
เจอราร์ดโอนีล

2
การตัดสินใจนี้ลดลงในภายหลังเมื่อ: msdn.microsoft.com/en-us/library/ …
Mark Sowul

310

คุณยังสามารถใช้

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

ฉันไม่คิดว่ามันจะมีประสิทธิภาพน้อยกว่า แต่ฉันก็ไม่สามารถสาบานได้ นอกจากนี้ยังให้คุณเลือกการเข้ารหัสที่แตกต่างกันในขณะที่ใช้ StreamReader คุณจะต้องระบุว่าเป็นพารามิเตอร์


6
การเข้ารหัสอยู่ใน System.Text namespace
northben

2
ฉันกำลังมองหา PowerShell ที่เทียบเท่ากับสิ่งนี้และต้องใช้มัน ([System.Text.Encoding] :: ASCII) .GetString (ms.ToArray ())
ลูอิส

โซลูชันนี้มีประโยชน์เนื่องจากสามารถใช้งานได้หลังจากปิด MemoryStream
Jacob Horbulyk

2
FWIW ฉันพบว่าสิ่งนี้ไม่ทำงานกับสตริงที่มีขนาดใหญ่มากฉันได้รับOutOfMemoryExceptions ใช้StreamReaderแทนการแก้ไขปัญหา
Grant H.

เนื่องจากอาจเป็นข้อผิดพลาด: ไม่ทราบถึงเครื่องหมายคำสั่งซื้อแบบไบต์และอาจรวม Hex 00ในตอนต้นของสตริง 00 3C 3F-> .<?ใน Hex แก้ไข แต่ใน VS หรือ Notepad <?++: ดังนั้นคุณจะไม่เห็นความแตกต่างแม้ว่าคุณจะเปรียบเทียบสตริงด้วยตาเพียงเครื่องมือเปรียบเทียบหรือเครื่องมือแก้ไข Hex จะแสดงความแตกต่าง ถ้าคุณยังใช้มันให้คิดถึง String.TrimStart ดู: docs.microsoft.com/en-us/dotnet/api/…
Skalli

99

การใช้ StreamReader เพื่อแปลง MemoryStream เป็น String

<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
คำชี้แจงการใช้งานจะช่วยให้มั่นใจว่า StreamReader ของคุณจะถูกกำจัด แต่เอกสารระบุว่า StreamReader จะปิดสตรีมพื้นฐานเมื่อได้รับการกำจัด ดังนั้นวิธีการของคุณปิด MemoryStream ที่ได้รับผ่านซึ่งเป็นแนวคิดที่ไม่บริสุทธิ์สำหรับผู้โทรแม้ว่าฉันสงสัย MemoryStream.Dispose ไม่มาก
Trillian

คุณถูก. โดยทั่วไปแล้วมันเป็นความคิดที่ดีที่จะใช้วิธีการกำจัดในชั้นเรียนสตรีมตัวช่วยโดยเฉพาะอย่างยิ่งถ้ากระแสถูกส่งผ่านไปยังวิธีการเป็นพารามิเตอร์ ฉันจะอัปเดตคำตอบนี้ ฉันยังมีคำตอบที่สมบูรณ์ยิ่งขึ้นด้านล่าง
Brian

หากคุณถอดรหัสคลาสเหล่านั้นคุณจะเห็นว่าวิธีการจัดการเพียงเรียก Dispose () บนสตรีมใด ๆ ที่ไม่เป็นโมฆะในอินสแตนซ์ (TextWriter, MemoryStream ฯลฯ )
Sinaesthetic

39

ใช้StreamReaderจากนั้นคุณสามารถใช้ReadToEndวิธีการที่ส่งกลับสตริง


12
ผมแค่อยากจะกล่าวถึงว่าBasestreamควรจะได้มีการกำหนดตำแหน่งในการ 0. memoryStream.Position = 0;ชอบ
Aykut Çevik

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.