【问题标题】:How do you get a string from a MemoryStream?如何从 MemoryStream 中获取字符串?
【发布时间】:2010-09-09 20:12:11
【问题描述】:

如果给我一个MemoryStream,而我知道它已经填充了String,我该如何找回String

【问题讨论】:

  • 永远无法确定是否始终需要 reader.close。我过去遇到过问题,所以通常我总是为了安全起见。

标签: .net vb.net string memorystream


【解决方案1】:

此示例展示了如何读取字符串并将其写入 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

【讨论】:

  • 当函数超出范围时,它不会处理 StreamWriter 吗?
  • 当变量超出范围时不会调用 Dispose。 Finalize 将在 GC 处理它时被调用,但 Dispose 是必须在变量超出范围之前调用的东西。我没有在上面调用它,因为我知道 StreamWriter 和 StreamReader 的实现不需要调用 Dispose,它只是将调用传递给底层流。但是,可以为任何实现 IDisposable 的东西调用 Dipose 提出合理的论据,因为您不能保证未来的版本不会要求它被释放。
  • @MichaelEakins 当问题被标记为 VB.Net 时,为什么答案甚至应该在 C# 中?
  • 我很高兴了解到“助手”将 dispose 调用传递到其底层流,但这似乎是一个糟糕的设计决定。
  • 这个决定后来被缓和了:msdn.microsoft.com/en-us/library/…
【解决方案2】:

你也可以使用

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

我不认为这效率较低,但我不能发誓。它还允许您选择不同的编码,而使用 StreamReader 您必须将其指定为参数。

【讨论】:

  • 编码在 System.Text 命名空间中
  • 我正在寻找与此等效的 PowerShell 并且不得不使用它。 ([System.Text.Encoding]::ASCII).GetString(ms.ToArray())
  • FWIW,我发现这不适用于非常大的字符串,我得到了OutOfMemoryExceptions。改用StreamReader 解决了这个问题。
  • 如果你的内容是UTF8你也可以System.Text.UTF8.GetString(ms.ToArray())
  • @Jirapong,在 2020 年使用 UTF8 是一个很好的评论,但在 .NET Framework 4.x 上,您的代码不起作用。相反,它通过Encoding.UTF8.GetString(ms.ToArray() 成功。也许您的代码错误或针对 .NET 核心?尽管如此:谢谢!
【解决方案3】:

使用 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

【讨论】:

  • 将 Position 设置为 0 会限制方法的重用能力——最好让调用者来管理它。如果流包含字符串之前的数据,调用者知道如何处理怎么办?
  • using 语句将确保您的 StreamReader 被释放,但文档说 StreamReader 在释放时关闭底层流。因此,您的方法会关闭它传递的 MemoryStream,即使我怀疑 MemoryStream.Dispose 做的很多,这在概念上对调用者来说也不酷。
  • 你是对的。在流助手类上使用 Dispose 方法通常是一个坏主意,尤其是在流作为参数传递给方法的情况下。我会更新这个答案。我在下面也有更完整的答案。
  • 如果你反编译这些类,你会看到 dispose 方法只是对实例中不为空的任何流(TextWriter、MemoryStream 等)调用 Dispose()
【解决方案4】:

使用StreamReader,然后您可以使用返回字符串的ReadToEnd 方法。

【讨论】:

  • 我只想提一下,Basestream 应该将其位置设置为 0。就像 memoryStream.Position = 0;
【解决方案5】:
byte[] array = Encoding.ASCII.GetBytes("MyTest1 - MyTest2");
MemoryStream streamItem = new MemoryStream(array);

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

【讨论】:

    【解决方案6】:

    以前的解决方案在涉及编码的情况下不起作用。这是 - 一种“现实生活” - 示例如何正确地做到这一点......

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

    【讨论】:

      【解决方案7】:

      在这种情况下,如果你真的想简单地使用MemoryStream中的ReadToEnd方法,你可以使用这个扩展方法来实现:

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

      【讨论】:

        【解决方案8】:

        这个示例展示了如何从 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
            }
        }
        

        【讨论】:

          【解决方案9】:

          为什么不在 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 来实现并发。

          【讨论】:

            【解决方案10】:

            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
            

            【讨论】:

            • 它确实对 Brian 的回答没有任何新意
            【解决方案11】:

            我需要与一个需要写入 Stream 的类集成:

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

            【讨论】:

              【解决方案12】:

              只使用 Convert.ToBase64String 方法

              Convert.ToBase64String(inputStream.ToArray());
              

              【讨论】:

              • 如果内容只是明文,为什么要使用 ToBase64String?
              猜你喜欢
              • 2017-05-17
              • 1970-01-01
              • 2021-04-15
              • 2011-11-30
              • 2017-07-28
              • 2012-07-23
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多