Làm thế nào để bạn có được một chuỗi từ MemoryStream?


532

Nếu tôi được cho một MemoryStreamcái mà tôi biết đã được điền vào a String, làm thế nào để tôi thoát Stringra?


1
Không bao giờ hoàn toàn chắc chắn nếu reader.close luôn luôn được yêu cầu. Tôi đã có vấn đề trong quá khứ vì vậy như một quy tắc tôi luôn luôn làm chỉ để ở bên an toàn.
Giòn

Câu trả lời:


468

Mẫu này cho biết cách đọc và viết một chuỗi vào 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
Không phải nó sẽ loại bỏ StreamWriter khi chức năng vượt quá phạm vi sao?
Tim Keat

14
Vứt bỏ không được gọi khi một biến đi ra khỏi phạm vi. Hoàn thiện sẽ được gọi khi GC đi xung quanh nó, nhưng Vứt bỏ là thứ phải được gọi trước khi biến đi ra khỏi phạm vi. Tôi không gọi nó ở trên vì tôi biết việc triển khai StreamWriter và StreamReader không yêu cầu Dispose để được gọi, nó chỉ chuyển cuộc gọi đến luồng bên dưới. Tuy nhiên, một đối số hợp pháp có thể được đưa ra để gọi Dipose cho bất kỳ điều gì thực hiện IDis Dùng vì bạn không thể đảm bảo bản phát hành trong tương lai sẽ không yêu cầu xử lý.
Brian

12
@MichaelEakins Tại sao câu trả lời thậm chí phải có trong C #, khi câu hỏi được gắn thẻ là VB.Net?
Rowland Shaw

1
Tôi rất vui vì đã biết về "người trợ giúp" chuyển cuộc gọi xử lý đến các luồng cơ bản của họ, nhưng đây có vẻ là một quyết định thiết kế tồi.
Gerard ONeill 17/07/13

2
Quyết định này đã được giảm nhẹ sau đó: msdn.microsoft.com/en-us/l
Library / Wiêu

310

Bạn cũng có thể dùng

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

Tôi không nghĩ rằng nó kém hiệu quả hơn, nhưng tôi không thể thề với nó. Nó cũng cho phép bạn chọn một mã hóa khác, trong khi sử dụng StreamReader, bạn phải chỉ định đó là một tham số.


6
Mã hóa nằm trong không gian tên System.Text
phía bắc

2
Tôi đã tìm kiếm tương đương PowerShell của cái này và phải sử dụng cái này. ([System.Text.Encoding] :: ASCII) .GetString (ms.ToArray ())
Lewis

Giải pháp này rất hữu ích vì nó có thể được sử dụng sau khi đã đóng MemoryStream.
Jacob Horbulyk

2
FWIW, tôi thấy điều này không hoạt động với các chuỗi rất lớn, tôi đã nhận được OutOfMemoryExceptions. Sử dụng StreamReaderthay vì giải quyết vấn đề.
Cấp H.

Vì đây có thể là một cạm bẫy: Nó không nhận biết dấu thứ tự byte và có thể bao gồm một Hex 00ở đầu chuỗi. 00 3C 3F-> .<?trong Hex Editor nhưng trong VS hoặc Notepad ++ : <?. Vì vậy, bạn không thể thấy sự khác biệt ngay cả khi bạn so sánh các chuỗi bằng mắt, chỉ một công cụ so sánh hoặc trình soạn thảo Hex sẽ hiển thị sự khác biệt. Nếu bạn vẫn sử dụng nó, hãy nghĩ về String.TrimStart. Xem: docs.microsoft.com/en-us/dotnet/api/ từ
Skalli

99

Sử dụng StreamReader để chuyển đổi MemoryStream thành Chuỗi.

<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
Đặt Vị trí thành 0 giới hạn khả năng sử dụng lại của phương thức - tốt nhất là để người gọi quản lý việc này. Điều gì xảy ra nếu luồng chứa dữ liệu trước chuỗi, mà người gọi biết cách xử lý?
Alex Lyman

1
Câu lệnh sử dụng sẽ đảm bảo rằng StreamReader của bạn được xử lý, nhưng tài liệu nói rằng StreamReader sẽ đóng luồng bên dưới khi nó được xử lý. Do đó, phương thức của bạn sẽ đóng MemoryStream mà nó được thông qua, điều này không có ý nghĩa đối với người gọi ngay cả khi tôi nghi ngờ MemoryStream.Dispose làm được nhiều điều.
Trillian

Bạn nói đúng. Thông thường, một ý tưởng tồi là sử dụng phương thức Vứt bỏ trên các lớp của trình trợ giúp luồng, đặc biệt nếu luồng được truyền vào một phương thức làm tham số. Tôi sẽ cập nhật câu trả lời này. Tôi cũng có một câu trả lời đầy đủ hơn dưới đây.
Brian

Nếu bạn dịch ngược các lớp đó, bạn sẽ thấy rằng phương thức xử lý đơn giản gọi là Dispose () trên bất kỳ luồng nào không có giá trị trong trường hợp (TextWriter, MemoryStream, v.v.)
Sinaological

39

sử dụng StreamReader , sau đó bạn có thể sử dụng phương thức ReadToEnd trả về một chuỗi.


12
Tôi chỉ muốn đề cập rằng, Basestreamnên đặt Vị trí của nó thành 0. Thích 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

Các giải pháp trước đây sẽ không hoạt động trong trường hợp mã hóa có liên quan. Đây là - một loại "cuộc sống thực" - ví dụ làm thế nào để làm điều này đúng cách ...

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

Trong trường hợp này, nếu bạn thực sự muốn sử dụng ReadToEndphương thức MemoryStreammột cách dễ dàng, bạn có thể sử dụng Phương thức tiện ích mở rộng này để đạt được điều này:

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

Và bạn có thể sử dụng phương pháp này theo cách này:

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

Mẫu này cho biết cách đọc chuỗi từ MemoryStream, trong đó tôi đã sử dụng tuần tự hóa (sử dụng DataContractJsonSerializer), chuyển chuỗi từ một số máy chủ sang máy khách và sau đó, làm thế nào để khôi phục MemoryStream từ chuỗi được truyền dưới dạng tham số, sau đó , khử lưu trữ MemoryStream.

Tôi đã sử dụng các phần của các bài viết khác nhau để thực hiện mẫu này.

Hy vọng rằng điều này sẽ giúp.

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

Một phiên bản sửa đổi một chút của câu trả lời của Brian cho phép quản lý tùy chọn bắt đầu đọc, Đây dường như là phương pháp dễ nhất. có lẽ không phải là hiệu quả nhất, nhưng dễ hiểu và sử dụng.

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
nó thực sự không có gì mới đối với câu trả lời của Brian
Luis Filipe

5

Tại sao không tạo một phương thức mở rộng đẹp trên loại 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;
        }
    }
}

Tất nhiên, hãy cẩn thận khi sử dụng các phương pháp này kết hợp với các phương pháp tiêu chuẩn. :) ... bạn sẽ cần sử dụng streamLock tiện dụng đó nếu có, để đồng thời.


0

Tôi cần tích hợp với một lớp cần Luồng để viết trên đó:

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

Tôi tạo một lớp đơn giản có thể giúp giảm các dòng mã để sử dụng bội số:

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

sau đó bạn có thể thay thế mẫu bằng một dòng mã

var ret = MemoryStreamStringWrapper.Write(schema.Write);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.